Swift4 アプリ内課金ライブラリSwiftyStoreKitが便利

iOSのアプリ内課金処理は複雑でわかりづらい。 良いライブラリがないか探していたところ、SwiftyStoreKitが大変便利だったので忘備録として残しておく。 ここでの処理は非消耗型の課金アイテムとする。

github.com

SwiftyStoreKitを使えるように準備

podでインストールする。

pod 'SwiftyStoreKit'

インポートで宣言する。

import SwiftyStoreKit

下記コードをapplication(:didFinishLaunchingWithOptions)などに追加する。一度だけ呼ばれるべきだと書いてあるので。

Note that completeTransactions() should only be called once in your code, in application(:didFinishLaunchingWithOptions:).

// おまじないのようなもの。下記コードをapplication(:didFinishLaunchingWithOptions)などに追加しよう。
SwiftyStoreKit.completeTransactions(atomically: true) { purchases in
    for purchase in purchases {
        switch purchase.transaction.transactionState {
        case .purchased, .restored:
            if purchase.needsFinishTransaction {
                SwiftyStoreKit.finishTransaction(purchase.transaction)
            }
        // Unlock content
        case .failed, .purchasing, .deferred:
            break // do nothing
        }
    }
}

価格などのプロダクト情報を取得

SwiftyStoreKit.retrieveProductsInfo(["プロダクトID"]) { result in
    if let product = result.retrievedProducts.first {

        // ここでプロダクト情報が得られるので、うまく使いまわしたい。
        print("Product: \(product.localizedDescription), price: \(priceString)")

    } else if let invalidProductId = result.invalidProductIDs.first {
//        print("Invalid product identifier: \(invalidProductId)")
    } else {
//        print("Error: \(result.error)")
    }
}

初めて購入する場合の処理

SwiftyStoreKit.purchaseProduct("プロダクトID", quantity: 1, atomically: true) { result in
    switch result {
    case .success(let purchase):
//        print("Purchase Success: \(purchase.productId)")
        
        // 購入後の処理はここに記述しよう。例えばUser Default などのフラグを変更するとか。
        
    case .error(let error):
//        switch error.code {
//        case .unknown: print("Unknown error. Please contact support")
//        case .clientInvalid: print("Not allowed to make the payment")
//        case .paymentCancelled: break
//        case .paymentInvalid: print("The purchase identifier was invalid")
//        case .paymentNotAllowed: print("The device is not allowed to make the payment")
//        case .storeProductNotAvailable: print("The product is not available in the current storefront")
//        case .cloudServicePermissionDenied: print("Access to cloud service information is not allowed")
//        case .cloudServiceNetworkConnectionFailed: print("Could not connect to the network")
//        case .cloudServiceRevoked: print("User has revoked permission to use this cloud service")
        }
    }
}

リストア処理

SwiftyStoreKit.restorePurchases(atomically: true) { result in
    for product in result.restoredPurchases {
        if product.needsFinishTransaction {
            SwiftyStoreKit.finishTransaction(product.transaction)
        }
        
        if product.productId == "プロダクトID1" {
            // プロダクトID1のリストア後の処理を記述する
        } else if product.productId == "プロダクトID2" {
            // プロダクトID2のリストア後の処理を記述する
        }
        
    }
}