【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) に追加する。
// おまじないのようなもの。下記コードを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")
}
}
}
リストア処理
最後にリストア処理の紹介。restorePurchasesを呼び出すことで、購入済みのアイテムが配列で返ってくるので、for文で回してチェックすれば良い。
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のリストア後の処理を記述する
}
}
}