iOSAPP アプリ内課金について 忘備録

参考サイト アプリ内課金の実装方法 - TERAKOYA

setを宣言

配列、で構造体

  • 要素が重複しない。
  • 順番が保証されない

まさにアイテム課金用の配列と言ってもいい。

private var productManagers: Set<ProductManager> = Set()

//setで宣言したものに追加していく。
productManagers.insert(productManager)

  //SKProductは商品 クロージャー型の型を指定している 必ずクロージャーを利用する
    private var completionForProductidentifiers : (([SKProduct]?, NSError?) -> ())?

クラスfunc はインスタンス化しなくても呼び出せる。static funcのようなもの オーバーライドもできる

class ProductManager:NSObject,SKProductsRequestDelegate{
    //SKProduct商品 クロージャーの型をしてい 必ずクロージャーを利用する
    private var completionForProductidentifiers : (([SKProduct]?, NSError?) -> ())?

    class func productsWithProductIdentifiers(productIdentifiers: [String]!, completion:(([SKProduct]?, NSError)-> () )?){
        
          let productManager = ProductManager()
//クラスのインスタンスから、productsWithProductIdentifiers関数を呼び出している。
//クラスfuncなので、インスタンス化しなくても呼び出せる。
ここで初めてインスタンスができている
帰ってくるのは商品。

          productManager.completionForProductidentifiers = completion as? (([SKProduct]?, NSError?) -> ())
        
          //SKProductsRequest appストアに上げた情報を取得する
          let productRequest = SKProductsRequest(productIdentifiers: Set(productIdentifiers))
          productRequest.delegate = productManager
          productRequest.start()
//productManagersはskproduct requestの非同期の処理を 複数抱え込むもの。
          productManagers.insert(productManager)
        
     }

@optional - (void)requestDidFinish:(SKRequest *)request NS_AVAILABLE(10_7, 3_0);

SKRequestは型 第一のキーワード引数と内部引数は兼ねているので requestは内部引数

NS_AVAILABLE(10_7, 3_0); はマクロ 利用できるバージョンが書いてある。

PurchaseManager

/// シングルトン
private let purchaseManagerSharedManager = PurchaseManager()



  /// シングルトン 外側からsharedManagerを通して呼ばれる
    class func sharedManager() -> PurchaseManager{
        return purchaseManagerSharedManager;
    }
     //未処理のトランザクションがあればそれを利用 OS側がもつことが多い
        //バックグラウンドで、SKPaymentQueueを持ってくれている パスワードを入力して下さいと何回も出るときは
        //SKPaymentQueueが溜まっているということ
        let transactions = SKPaymentQueue.default().transactions
        if transactions.count > 0 {
            for transaction in transactions {
                if transaction.transactionState != .purchased {
                    continue
                }
 //すでに購入したものを買うと、買いましたよと言ってくれる 間違えて2回押しても、もう購入しましたよと教える
                // 非消耗型 機能開放するなど 別のコンテンツを買うのなら非消耗型
                //コンテンツ配信は非消耗型、200円とか値段がついて入れば
                //通貨は消耗型 通貨で買わせればいい
//アプリ内の武器などは消耗型
                if transaction.payment.productIdentifier == product.productIdentifier {
                    if let window = UIApplication.shared.delegate?.window {
                        let ac = UIAlertController(title: nil, message: "\(product.localizedTitle)は購入処理が中断されていました。\nこのまま無料でダウンロードできます。", preferredStyle: .alert)
                        let action = UIAlertAction(title: "続行", style: UIAlertAction.Style.default, handler: {[weak self] (action : UIAlertAction!) -> Void in
                            if let weakSelf = self {
                                weakSelf.productIdentifier = product.productIdentifier
                                weakSelf.completeTransaction(transaction)
                            }
                        })
                        ac.addAction(action)
                        window!.rootViewController?.present(ac, animated: true, completion: nil)
                        return
                    }
                }
            }
   //課金処理開始 未処理のトランザクションがない場合 普通の課金処理
        let payment = SKMutablePayment(product: product)
        SKPaymentQueue.default().add(payment)
        self.productIdentifier = product.productIdentifier
    }


1.Viewcontrollerで商品陳列する 2.どんな商品があるかは、ProductManagerクラスが管理 3.購入は、PurchaseManager startwithproductが呼ばれる

ProductManagerはどれがいくらか書いているだけ 販売停止にしたりするので、分けておいたほうがいい。 値段とかも変更できるので。

課金で難しいのは、サーバーの実装が絡む時

課金しましたよをアプリ内で保持するのは簡単。 サーバーに買いましたよというAPIを投げたときに、 アップルに検証する。 レシートの検証をする。

アプリ内にしておいたほうがいい。 リクエストの改ざんは簡単にでききる けんしょうるための仕組みが大変

サーバーで課金情報を保持するか?

このユーザーはこのアイテムを買いましたー>危険です。

アプリの外に出さない。通信しないほうがいい。 userdefaultに暗号化して保持しておく。 userdefaultはあまりセキュアでないので、暗号化して持っておく。

OSまたぐと、サーバーで課金情報持たないといけない

ゲームのアイテム等、消耗型はosで保持できないのでむつかしい。