今回のエンジニアブログを担当する村田です。Consumable(消費型)アプリ内課金を実装して分かったはまりどころをポイントで説明します。
1.レビュー時におけるStoreレシートの確認先
アプリ内課金では、有効なトランザクションである事を確認するためにレシートデータをAppStoreへ送信します。
Storeレシートの確認先は「In-App Purchaseプログラミングガイド」によると下記のとおりです。
環境 | 送信先 |
製品時 | 本番環境 |
開発時 | サンドボックス環境 |
では、レビュー時は?
プロダクトモジュールを送付するので...本番URL?
と判断し実装するとはまります。
レビュー時は、サンドボックス環境を利用します。
環境 | 送信先 |
開発時 | サンドボックス環境 |
製品時 | 本番環境 |
レビュー時 | サンドボックス環境 |
と、なります。
環境に応じて切り替えていると障害を埋め込む原因となります。
では、どう実装するのが良いのか?
そのヒントは、Storeレシート確認結果のCodeにあります。
確認結果のCodeは以下のとおりです。
Code | Status |
21000 | Bad JSON |
21002 | Malformed |
21003 | Auth Error |
21004 | Auth Failed |
21005 | Service Unavailable |
21006 | Inactive |
21007 | Sandbox receipt in Prod |
21008 | Prod receipt in Sandbox |
ここで注目するのはCode「21007」です。
サンドボックス環境で取得したレシートを本番環境に送信した時に返ってくるコードになります。
これを利用して、本番環境・サンドボックス環境を意識しない実装を行います。
実装する処理フローを以下に示します。
- レシートを本番環境へ送信する
- 戻り値を確認
- Codeが"0"の場合は、成功処理へ
- Codeが"21007"の場合は、サンドボックス環境へ送信する
- 戻り値を確認
- Codeが"0"の場合は、成功処理へ
- Codeが上記以外の場合は、エラー処理へ
- 戻り値を確認
- Codeが上記以外の場合は、エラー処理へ
2.ペイメントキューにオブザーバーとして追加するタイミング
アプリケーションが起動してから早いタイミングで追加するべきと、
iOS Developer Libraryの「In-App Purchase Programming Guide」
に記載されています。
例えば次のように実装すると、どうなるでしょう?
「購入」ボタンタップ時の例
1.SKPaymentQueueへオブザーバーとして追加
2.SKPaymentをSKPaymentQueueへaddPayment
3.Apple側の処理待ち
4.アプリ内課金処理が終了した時にfinishTransactionを呼び出しトランザクションを完了
5.SKPaymentQueueへ追加したオブザーバーを削除
一見、正しい処理フローに見えます。
しかし『3.Apple側での処理待ち』のところでアプリケーションを終了させると、どうなるでしょう。
トランザクションは、finishTransactionを呼び出すまでデバイス内に存在します。
しかも、アプリケーションを削除、デバイスの電源を切っても存在し続けます。
よって、再度「購入」ボタンをタップ(アプリ内課金)すると
SKPaymentQueueへオブザーバーとして追加される
↓
前回追加しデバイスに残っていたトランザクションが再開される
↓
前回未完了のトランザクションが終了
↓
オブザーバーが削除される
↓
先ほど追加したSKPaymentは処理が完了せずデバイス内に残る
となり、SKPaymentが残り続ける状態となってしまいます。
この状態を防ぐためには
■アプリケーション起動時
1.SKPaymentQueueへオブザーバーとして追加
■アプリ内課金処理時
1.SKPaymentをSKPaymentQueueへaddPayment
2.Apple側の処理待ち
3.アプリ内課金処理が終了した時にfinishTransactionを呼び出しトランザクションを完了
と、実装しましょう。