StoreKit トランザクションの中断と再開

購入トランザクションは、アプリが最後にfinishTransaction:を呼んだタイミングで完了となりますが、そこにたどり着く前にアプリケーションが終了してしまったりネットが切断してしまう可能性があります。その場合、トランザクションは未完状態になり、次回アプリケーションが起動したタイミングで再開されます。これを適切に処理しようとすると、結構厄介なことに気がつきます。

トランザクションの中断

トランザクションを意図的に未完状態にする方法はいくつかあります。購入ダイアログがでた直後にアプリケーションを終了してしまってもいいし、もっとシンプルにPaymentをキューに積んだ後、finishTransactionを呼ばなければそのトランザクションは未完状態のまま残る事になります。

トランザクションの再開

未完状態のトランザクションは、次回アプリケーションが起動した後でStoreKitからSKPaymentTransactionObserverプロトコルを通じてアプリケーションに通知されます。従って、In App Purchase Programming Guideでも指示されているようにObserverの登録は基本的にはアプリケーションの起動直後に行うべきです。

UIとゲームロジック上の問題

このような仕組みのため、アプリケーションは基本的にはどのタイミングでもアプリ内課金に関する処理を行えるようにしておく必要があります。そして、これは色々な場面で結構面倒くさいことになります。
例えば、アプリ内課金を実装する場合、基本的には「購入」のUIを作る事になります。StoreKitを使った購入手続きは結構時間がかかるので、その間アプリケーションのUI側でもインジケータを表示したりボタンを非表示にするなどしてユーザが他の操作をできないようにして、「購入完了」の通知がきたタイミングでそれらを元に戻す、というようなことをやることになります。ところが、UIを表示しているわけではないのに未完トランザクションが完了したタイミングでも「購入完了」が来てしまうので、これを適切に処理しなければいけなくなります。
UIだけならまだ良いですが、これがプレイ中のゲームに影響があるアイテム(ライフの数等)であった場合、まさにゲームをプレイしている最中にトランザクションが再開/完了したらどうするべきか、というような問題もあります。話がややこしくなるので今回は省略しますが、サーバープロダクトモデルの場合にはさらに厄介になります。

タイミングの問題

未完状態のトランザクションの再開は、transactionStateがSKPaymentTransactionStatePurchasedに変化したことの通知でアプリケーション側に伝えられますが、厄介なのはアプリを起動してからこの通知がくるまでに若干の時差があることです。手元の端末(iPhone 3GS / iPhone 4S)で試してみたところ、Sandbox環境ですが、これらの通知がくるまで通信状態が良好な状態で10秒前後かかります。通信状態がよくない状態で試すと、さらにこの間隔は不安定になります。

再購入の問題

次のポストで見ていきますが、未完トランザクションがある状態でもう一度Paymentをリクエストすると、新しいトランザクションが作成された後それが失敗して古いトランザクションが再開される、というアプリケーション側から見ると「今どういう状況なのか」とてもわかりにくい現象が起きます。

ログインダイアログの問題

購入のトランザクションはApple IDと紐づいています。アイテムを購入しようとするときに、AppStoreへの認証が切れていた場合は右図のような認証ダイアログが表示され、既に認証済みだった場合はこのダイアログが表示されることなく購入は進んでいきます。
未完トランザクションの再開も、なぜかこの認証が求められます。前回購入が途中で中断してしまって、すぐに再起動したような場合であれば認証ダイアログがでることなくトランザクションが再開されるので問題ないのですが、認証が切れてしまっていた場合はダイアログが表示されます。認証が切れる期間/条件については明記がありませんが、試しに二台のデバイスで交互にアプリ内課金をしようとしてみたところ、一方のデバイスで認証を行った後は他方のデバイスでは再認証(パスワードの入力)が求められるようになりました。
問題はこのダイアログがトランザクション再開のタイミング、つまりObserverを登録したタイミング、すなわちアプリケーションの起動後数秒後に唐突に表れることです。なんの前触れもなく突然Apple IDの認証ダイアログがでてくるため、ユーザは戸惑ってしまいます。
が、残念ながらこの問題を回避する方法はなさそうです…。

未完トランザクションの判定

最も厄介なのは、このトランザクションの再開のタイミングが上記のように環境によって左右されるにも関わらず、アプリ側からは未完トランザクションが存在するかどうか、未完トランザクションの再開が開始/完了したのかどうか、あるいは現在実行中のトランザクションが未完トランザクションが再開したものなのか、ユーザが購入ボタンを押すことによって開始した新しいトランザクションなのかどうか知るためのAPIがないことです。このAPIがあればこれらの諸問題を回避できるのですが、残念ながら2011年10月現在のIn App Purchase Programming GuideおよびStoreKit Framework Referenceを見ている限りではそのための仕組みがないようです。従って、この問題を解決するために様々な対応をいれていかなければいけません。
さて、もう少し細かく未完トランザクションの動きを見ていきます。

Pocket

「StoreKit トランザクションの中断と再開」への4件のフィードバック

  1. >問題はこのダイアログがトランザクション再開のタイミング、つまりObserverを登録したタイミング
    とありますが、observerを登録しなくても
    [SKPaymentQueue defaultQueue]を呼ぶだけで現れます。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です