In-App Purchaseの処理を書くのは結構めんどくさい。できるだけメインの実装にコストを掛けて、サブ的な実装にはあまりコストを掛けたくないものです。
この記事ではSwiftを利用したアプリ内課金をできるだけコピペだけで実装できるように紹介します。
SwiftyStoreKitの準備
Xcodeへのインストール
タイトル通りIn-App Purchaseの実装にはSwitfyStorekitを使用します
あらかじめ、CocoaPodやCarthageを使ってXcodeインストールしてください。
AppDelegateへの実装
AppDelegate
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// see notes below for the meaning of Atomic / Non-Atomic
SwiftyStoreKit.completeTransactions(atomically: true) { purchases in
for purchase in purchases {
switch purchase.transaction.transactionState {
case .purchased, .restored:
if purchase.needsFinishTransaction {
// Deliver content from server, then:
SwiftyStoreKit.finishTransaction(purchase.transaction)
}
// Unlock content
case .failed, .purchasing, .deferred:
break // do nothing
}
}
}
return true
}
Swiftファイルへのimport
import
import SwiftyStoreKit
Swift実装
価格の取得
func
func purchaseGetInfo(PRODUCT_ID:String) {
SwiftyStoreKit.retrieveProductsInfo([PRODUCT_ID]) { result in
if let product = result.retrievedProducts.first {
//未購入の場合
} else {
//購入済みの場合
}
}
}
呼び出し
purchaseGetInfo(PRODUCT_ID: "")
MEMO
呼び出し時にご自身のアプリ内課金の製品IDをPRODUCT_IDとして渡してください。消費・非消費型課金
function
func purchase(PRODUCT_ID:String){
SwiftyStoreKit.purchaseProduct(PRODUCT_ID, quantity: 1, atomically: true) { result in
switch result {
case .success(_):
//購入成功
//購入の検証
self.verifyPurchase(PRODUCT_ID: PRODUCT_ID)
case .error(_):
//購入失敗
}
}
}
func verifyPurchase(PRODUCT_ID:String){
let appleValidator = AppleReceiptValidator(service: .production, sharedSecret: SECRET_CODE)
SwiftyStoreKit.verifyReceipt(using: appleValidator) { result in
switch result {
case .success(let receipt):
let purchaseResult = SwiftyStoreKit.verifyPurchase(productId: PRODUCT_ID, inReceipt: receipt)
switch purchaseResult {
case .purchased:
//リストアの成功
case .notPurchased:
//リストアの失敗
}
case .error:
//エラー
}
}
}
MEMO
functionのSECRET_CODEにはご自身のアプリ内課金のApp用共有シークレットそして生成された共有シークレットを入力してください。 呼び出し
purchase(PRODUCT_ID: "")
MEMO
呼び出し時にご自身のアプリ内課金の製品IDをPRODUCT_IDとして渡してください。非消費課金のリストア
メソッドを利用した方法
function
SwiftyStoreKit.restorePurchases(atomically: true) { results in
if results.restoreFailedPurchases.count > 0 {
//リストアに失敗
}
else if results.restoredPurchases.count > 0 {
//リストアに成功
}
else {
//リストアするものがない
}
}
レシート検証を利用した方法
function
func restorePurchase(PRODUCT_ID:String) {
SwiftyStoreKit.fetchReceipt(forceRefresh: true) { result in
switch result {
case .success(_):
//レシートの取得
self.verifyPurchase(PRODUCT_ID: PRODUCT_ID)
case .error(_):
//レシートの取得失敗
}
}
}
func verifyPurchase(PRODUCT_ID:String){
let appleValidator = AppleReceiptValidator(service: .production, sharedSecret: SECRET_CODE)
SwiftyStoreKit.verifyReceipt(using: appleValidator) { result in
switch result {
case .success(let receipt):
let purchaseResult = SwiftyStoreKit.verifyPurchase(productId: PRODUCT_ID, inReceipt: receipt)
switch purchaseResult {
case .purchased:
//リストアの成功
case .notPurchased:
//リストアの失敗
}
case .error:
//エラー
}
}
}
MEMO
functionのSECRET_CODEにはご自身のアプリ内課金のApp用共有シークレットそして生成された共有シークレットを入力してください。 呼び出し
restorePurchase(PRODUCT_ID: "")
MEMO
呼び出し時にご自身のアプリ内課金の製品IDをPRODUCT_IDとして渡してください。更新型課金
function
func purchase(PRODUCT_ID:String){
SwiftyStoreKit.purchaseProduct(PRODUCT_ID, quantity: 1, atomically: true) { result in
switch result {
case .success(_):
//購入成功
//購入の検証
self.verifyPurchase(PRODUCT_ID: PRODUCT_ID)
case .error(_):
//購入失敗
}
}
}
func verifyPurchase(PRODUCT_ID:String){
let appleValidator = AppleReceiptValidator(service: .production, sharedSecret: SECRET_CODE)
SwiftyStoreKit.verifyReceipt(using: appleValidator) { result in
switch result {
case .success(let receipt):
//自動更新
let purchaseResult = SwiftyStoreKit.verifySubscription(
ofType: .autoRenewable,
productId: PRODUCT_ID,
inReceipt: receipt)
//自動更新なし(30日間)
//let purchaseResult = SwiftyStoreKit.verifySubscription(
ofType: .nonRenewing(validDuration: 3600 * 24 * 30),
productId: PRODUCT_ID,
inReceipt: receipt)
switch purchaseResult {
case .purchased:
//リストアの成功
case .notPurchased:
//リストアの失敗
}
case .error:
//エラー
}
}
}
MEMO
functionのSECRET_CODEにはご自身のアプリ内課金のApp用共有シークレットそして生成された共有シークレットを入力してください。 呼び出し
purchase(PRODUCT_ID: "")
MEMO
呼び出し時にご自身のアプリ内課金の製品IDをPRODUCT_IDとして渡してください。 実装方法について
上記のそれぞれの実装にはverifyPurchase,purchaseなど同じ部分が多く含まれています。複数の実装をコピーペーストするとエラーが発生しますのでご注意ください。
また、更新型課金と非消費・消費型課金を同時にご使用になる際は、ifやswitch等で場合分けして、もしくはfuncの内部だけ取り出してご利用ください。
SwitfyStoreKitの参考で大変助かっております。
一つ教えてほしいのですが
アプリ起動時に購入済かどうかを行う処理が分からなく どうしてるのでしょうか?
ありがとうございます。
アプリ起動時に上に書いてある通り消費型の課金要素であれば「価格の取得」などをすれば購入済みかどうかのチェックはできるかと思います。(ただAppleのサーバとの通信が入るため多少の時間がかかってしまいます)
私の場合だと、UserDefaultsなどの永久保存できる方法で、課金されたときに課金済みかどうかの情報を保存する方法をとっています。
ご返信ありがとうございます。
こちらは自動継続課金でやっているのですが、sandboxで課金完了後及びアプリ再起動し、purchaseGetInfoでなぜか未購入処理が走ってしまいます。
課金完了時にUserDefaultsに課金済を記録する方向で作ってみます。