StoreKitのトランザクションには、トラブルが発生した際に重要になる情報が多く含まれています。SKPaymentTransactionオブジェクトに含まれる情報と、それらの挙動について確認していきましょう。なお、複雑になるのでNon-Consumableプロダクトのリストア関連の項目については、基本的に省略しています。
SKPaymentTransactionの要素
SKPaymentTransactionに含まれる主なプロパティは以下の通りです。(Non-Consumableプロダクトのリストア関連の要素は除いています)
各要素について、挙動や使い方を確認していきましょう。
transactionState
トランザクションがどういった状況にあるのか、を表すプロパティです。アプリケーション側からはこれをみて、トランザクションが実行中なのか、成功したのか、失敗したのかを判断し、UIを操作することになります。
transactionStateには下記の四つのステートがあります。
SKPaymentTransactionStatePurchasing | 購入を開始しようとした状態。「購入しますか?」ダイアログが表示されるよりも前にこの状態になります。 |
SKPaymentTransactionStatePurchased | 「購入する」を押してパスワード認証を終えて少しするとこの状態になります。 |
SKPaymentTransactionStateFailed | なんらかのエラーが発生してトランザクションが正しく終了しなかった状態。「購入しますか?」ダイアログでキャンセルが押された場合にもこの状態になります。 |
SKPaymentTransactionStateRestored | Non-consumableなプロダクトの復帰用。割愛。 |
トランザクションのステートが変わると、SKPaymentQueueのオブザーバー側でデリゲートメソッドが呼び出されます。
transactionIdentifier
トランザクションを識別するためのIDです。トラブルが発生したときに、どの決済手続きで問題が発生したかを特定する上でとても重要な値です。ただし、このプロパティに含まれる値はタイミング/ステートによって変化するので注意が必要です。
Class Referenceによれば、
The contents of this property are undefined except when transactionState is set to SKPaymentTransactionStatePurchased or SKPaymentTransactionStateRestored.
と書いてあり、transactionStateがPurchasedかRestoredの時以外にこのプロパティにセットされている値は未定義、となっています。つまり、トランザクションが失敗したときにここに入っている値については、内容が保証されていません。
transactionIdentifierがどのような値になるか、実際に実験(iPhone 4S, iOS 5.0.1, Sandbox)で試してみたところ、下記の用な感じになりました。
ステート | 値 | サンプル |
---|---|---|
Purchasing | (null) | (null) |
Purchased | 番号的な文字列 | 123456789012 |
Failed(意図的にキャンセルした場合) | UUID的な文字列 | 4A5925F8-6FFD-4506-B1DD-**** |
Failed(別のトランザクションが再開した場合) | UUID的な文字列 | 7A6582BF-AC0F-4BB1-9AA2-**** |
トランザクションが途中で中断され、再開された場合のtransactionIdentifierは中断されたものと同じ文字列になるようです。
transactionDate
トランザクションがキューに追加された日時が保存されています。この値についても、Purchased / Restoredの時以外に含まれる値は未定義なので注意が必要です。
The date the transaction was added to the App Store’s payment queue.
ドキュメントにはこのような定義がありますが、「App Storeのキューに追加される」というのがどのタイミングなのか厳密な説明は見つかりませんでした。実験してみたところ、下記のような値になりました。
18:02:38 Transaction update.(Purchasing) -> transactionDate: (null) // ここで「購入しますか?」ダイアログが表示される // 意図的に2分程放置、その後「購入」 18:04:39.064 Transaction update.(Purchased) -> transactionDate: 2012-02-24 09:04:39 +0000
というわけで、「App Storeのキューに追加された」タイミングは、「購入」を押してステートがPurchasedになったタイミングとほぼ同じになるようです。ローカルでSKPaymentQueueに追加されたタイミングとは異なるようなので、注意しておきましょう。
ちなみに、この時刻はサーバー側での時刻になるようです。意図的に時計を30分ほどずらして試してみたところ、下記の用になりました。
18:40:53 Transaction update.(Purchasing) -> transactionDate: (null) 18:41:04 Transaction update.(Purchased) -> transactionDate: 09:11:13 +0000
Failedの時の値についてはnullになっていました。
transactionReceipt
決済が完了(Purchased)したときのみ参照できる、決済のレシート情報です。特にサーバーモデルのときには、サーバー側でその決済が有効であるかを検証する用途で使います。
長くなるので、別の機会に説明します。
payment
そのトランザクションが、どういったプロダクトに対する購入なのかを示すプロパティです。
error
トランザクションがFailした場合に、このプロパティにエラー情報が含まれます。
ドキュメントによると、
SKErrorUnknown | 何が起きたかよくわからない |
SKErrorClientInvalid | クライアントが許可されていない処理を行おうとした |
SKErrorPaymentCancelled | ユーザがキャンセルした |
SKErrorPaymentInvalid | 支払いリクエストの内容がおかしい |
SKErrorPaymentNotAllowed | アプリ内課金が制限されている(ペアレンタルコントロール等) |
の5つのエラーがありますが、なぜかどのエラーでもLocalizedDescriptionは「iTunes Storeに接続できません」になっているようです。
また、以前の記事で書いた通り、SKErrorPaymentCancelledに関してはユーザが意図的にキャンセルした場合も、トランザクションが再開されてキャンセルされた場合も同じ情報が返ってきてしまうので注意が必要です。
参考
SKPaymentTransaction Class Reference
なんでレシートでトランザクションIDが数字のみなのに文字列なの。と思ったらPurchasingとFailedで違った – SKPaymentTransactionについてkwsk | なんてこったいブログ: http://t.co/E0FGiWts #miteru