【Swift】SwiftyStoreKitでアプリ内課金の実装【iOSアプリ開発】

【Swift】SwiftyStoreKitでアプリ内課金の実装【iOSアプリ開発】
【Swift】SwiftyStoreKitでアプリ内課金の実装【iOSアプリ開発】

iOSのアプリ開発をしている上で、課金システムを導入する場合に処理が複雑で実装するにはハードルが高かった。そこで何か良いライブラリがないか探していたところ「SwiftyStoreKit」ライブラリを見つけた。実際使ってみたところ大変わかりやすく便利だったので、この記事では「SwiftyStoreKit」の使い方を説明していく。なお、この記事では「非消耗型の課金アイテム」を対象としている。

GitHub - bizz84/SwiftyStoreKit: Lightweight In App Purchases Swift framework

アプリ内課金を実現するSwiftyStoreKitのインストール

今回はpodでSwiftyStoreKitをプロジェクトから使えるようにしていく。pod 'SwiftyStoreKit'でSwiftyStoreKitをインストールしよう。そしてSwiftyStoreKitを使いたいクラスに、import SwiftyStoreKit を記述しておく。SwiftyStoreKitの初期化のために、下記コードを application(:didFinishLaunchingWithOptions) に追加する。

swift
// おまじないのようなもの。下記コードを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
        }
    }
}

説明では一度だけ呼ばれるべきだと書いてあるので注意しておく。

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

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

次の非同期処理で、価格などのプロダクト情報を取得することができる。少し時間がかかるので、呼び出すタイミングを工夫したい。

swift
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)")
    }
}

はじめて課金アイテム購入した場合の処理

はじめて課金アイテム購入した場合の処理は次の通り。成功したか失敗したかを返してくれるので、課金処理が非常にラク。

swift
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")
        }
    }
}

リストア処理

最後にリストア処理の紹介。restorePurchasesを呼び出すことで、購入済みのアイテムが配列で返ってくるので、for文で回してチェックすれば良い。

swift
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のリストア後の処理を記述する
        }
        
    }
}

関連記事

最後までご覧いただきありがとうございます!

▼ 記事に関するご質問やお仕事のご相談は以下よりお願いいたします。
お問い合わせフォーム