支払いは完了したのにアイテムがアンロックされない、等の問題が起きないように、StoreKitにはトランザクションの機構があります。トランザクションの機構は絶対に必要なのですが、これがStoreKitによるアプリ内課金の組み込みを複雑にする大きな要素となってきます。基礎から見ていきましょう。
StoreKitにおけるトランザクション
SKPaymentTransactionクラス
トランザクションを扱うクラスはSKPaymentTransactionです。基本的にPaymentがキューに積まれたタイミングで生成され、購入の一連の流れを管理するのに用います。最後はアプリケーション側からfinishTransaction:というトランザクション完了のメソッドを投げる形で完了になります。
SKPaymentTransactionObserverプロトコル
アプリケーション側がPaymentリクエストをStoreKitのキューに積んだ後、決済の処理は基本的にStoreKit側で進められていき、アプリケーション側はその進捗報告を待つ形になります。StoreKitから各トランザクションの進捗に対する通知はSKPaymentTransactionObserverプロトコルを使って通知されるので、アプリケーション側にはこのプロトコルに準拠するクラスを一つ用意する必要があります。In App Purchase Programming Guideによると、このObserverの登録はアプリケーション起動時に行うように指示されています。なお、addTransactionObserver:ではオブザーバーのretainが行われないので注意が必要です。
[[SKPaymentQueue defaultQueue] addTransactionObserver: [[MyStoreObserver alloc] init]];
SKPaymentTransactionObserverプロトコルで定義されているメソッドのうち、重要なのは- (void)paymentQueue:updatedTransactions:で、アプリケーション側はこれを使ってトランザクションの進捗を把握します。
@implementation MyStoreObserver - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions { for (SKPaymentTransaction *transaction in transactions) { switch (transaction.transactionState) { case SKPaymentTransactionStatePurchased: NSLog(@"purchased. %@", transaction); break; case SKPaymentTransactionStateFailed: NSLog(@"transaction failed. %@", transaction.error); break; case SKPaymentTransactionStateRestored: NSLog(@"transaction restored."); default: break; } } } @end
AppStoreでの決済が完了すると、トランザクションのtransactionStateがSKPaymentTransactionStatePurchasedになるので、ここでアプリケーション側でコンテンツのアンロック等を行い、最後にそのトランザクションに対してfinishTransaction:を送って購入手続きは完了です。
購入の失敗
購入トランザクションは毎回必ず成功するわけではありません。ユーザがApple IDによる認証に失敗したり、その他諸々の都合でトランザクションが失敗に終わった場合はトランザクションの状態がSKPaymentTransactionStateFailedとなります。これが結構複雑なので、ここは次のポスト以降で詳細に検証していきます。
トランザクションの中断と再開
購入手続きの途中でアプリケーションを終了したりすると、トランザクションはfinishされずに残る事になります。正しくfinishしなかったトランザクションは前回アプリケーションを起動したときにオブザーバー経由でアプリケーションに通知されます。これがなかなか厄介なのですが、まだまだ前提となる知識が必要なので次のポスト以降で。
はじめまして。ここ2年間、StoreKit(アプリ内課金)を中心に活動している者です。
自分とは違う発見、文章表現を求めてここにたどり着きました。
素晴らしい見識をお持ちで、私もいくつか参考にさせて頂きました。特に異常系に関する考察には「なるほど」と頷かされるものがありました。
ひとつおせっかいながら、背景情報としてどんなプロダクトを対象にしているのか?また、レシートに関する情報(有無を含め)を明確にされると、さらに素晴らしい情報になると思いました。
今後いっそうのご活躍を期待させていただきます。
ありがとうございます。レシート等については、また今後別の記事にて触れていきたいと思います。
最後の段落
>正しくfinishしなかったトランザクションは前回アプリケーションを起動したときにオブザーバー経由でアプリケーションに通知されます。
これは次回の間違いでは?
内容はすばらしい。