WonderPlanet DEVELOPER BLOG

ワンダープラネットの開発者ブログです。モバイルゲーム開発情報を発信。

iOSアプリ内課金(In-App Purchase)のはまりどころ

今回のエンジニアブログを担当する村田です。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」です。
サンドボックス環境で取得したレシートを本番環境に送信した時に返ってくるコードになります。
これを利用して、本番環境・サンドボックス環境を意識しない実装を行います。

実装する処理フローを以下に示します。

  1. レシートを本番環境へ送信する
  2. 戻り値を確認
    1. Codeが"0"の場合は、成功処理へ
    2. Codeが"21007"の場合は、サンドボックス環境へ送信する
      1. 戻り値を確認
        1. Codeが"0"の場合は、成功処理へ
        2. Codeが上記以外の場合は、エラー処理へ
    3. 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を呼び出しトランザクションを完了

と、実装しましょう。