SKPaymentTransactionについてkwsk

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

Pocket

「SKPaymentTransactionについてkwsk」への1件のフィードバック

コメントを残す

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