レシートのverifyとSandbox

StoreKitを使ってアプリ内でアイテムの購入が行われると、レシートが発行されます。Appleは不正防止のため、レシートの内容が正しいかどうかverifyする機構を用意していますが、この機構を使うには若干注意が必要です。

レシートの認証の基礎

まず、StoreKitを使ったアプリ内課金を実装する上で、レシートの認証はすべてのアプリで必須の要件というわけではありません。しかし、とくに購入内容がサーバーと連動するような場合において、レシートの認証は効果の高い不正対策方法の一つです。
ユーザがアプリ内で決済を行う(状態がSKPaymentTransactionStatePurchasedになる)と、そのtransactionのtransactionReceiptプロパティからレシートデータを取得できるようになります。ここで取得したレシートデータをAppleが用意している認証サーバー(buy.itunes.apple.com)に送信すると、正規のレシートかどうか(偽造されたものではないか)を返してくれる、というものです。組み込み方の詳細はIn-App Purchase Programming Guide: Verifying Store Receiptsを参照。

Sandbox問題

さて、問題は認証サーバーにあります。
StoreKitには、開発時に使うSandbox環境と実際に課金が発生するProduction環境があります。基本的にはAppStoreでリリースされたバイナリが自動的にProduction環境、開発時にXcodeからビルドしたバイナリではSandbox環境が使われるので、この二つの環境の切り替えを手動で行う必要はありません。しかし、レシートの認証サーバーは例外です。
先ほどあげたbuy.itunes.apple.comはProduction環境用で、Sandbox環境用にはsandbox.itunes.apple.comという別のサーバーが用意されています。予想通り、基本的にSandbox環境(開発時)のレシートはSandboxサーバーで、Production環境(リリース版)のレシートはProductionサーバーにてVerifyしなければいけません

サーバーの切り替え

「開発中はSandboxサーバーに向けておいて、アプリをサブミットしたらProductionに向ければいいや」。これはアプリがリリースされた後の課金部分の開発の際、運用上とても面倒くさいことになります。
では、どうやって切り替えたらいいのか。実はIn-App Purchase Programming Guideには特にその部分についての言及がありません…。

実行中の環境がSandboxかProductionか判定する?

実行中の環境がSandboxかProductionか知ることができれば、認証に使うサーバーを自動的に切り替えることができて、面倒なことなく運用できます。
しかし、残念ながらIn-App Purchase Programming Guideには実行中の環境がSandboxかProductionかを判定する方法については記述がありません。唯一、Sandboxか判定できそうな情報としては、SandboxサーバーとProductionサーバーでは認証APIの返り値に含まれるデコードされたレシートデータに含まれる項目が異なる、ということなのですが、これはサーバーにレシートの認証をリクエストした後の話なので、リクエストを送るサーバーを判断するタイミングでは使えません…。
実は、transactionReceiptの内容に

"environment" = "Sandbox";

というような文字列が含まれている、という情報もあるのですが、これについてはドキュメントで言及されておらず確かな仕様とはいえません。

正解

この問題に対する正解はTechnical Note TN2259のFAQ内に記述されていました。

How do I verify my receipt (iOS)?
Always verify your receipt first with the production URL; proceed to verify with the sandbox URL if you receive a 21007 status code. Following this approach ensures that you do not have to switch between URLs while your application is being tested or reviewed in the sandbox or is live in the App Store.

というわけで、とりあえず最初はProductionサーバーの方の認証APIを叩いてみて、status code: 21007が返ってきたらそれはSandbox用のレシートだからSandboxサーバーに問い合わせなおしてね、ということみたいです。
レシートの認証を導入して実際にアプリを運用する上でほぼ確実に問題になる箇所だと思うので、In-App Purchase Programming Guideに書いておいた方がいいような気がするので、Appleにフィードバック送ってみました。

Pocket

「レシートのverifyとSandbox」への4件のフィードバック

  1. http://t.co/k3lraCiL 「とりあえず最初はProductionサーバーの方の認証APIを叩いてみて、status code: 21007が返ってきたらそれはSandbox用のレシートだからSandboxサーバーに問い合わせなおしてね」
    とりあえず…

@f_rettu へ返信する コメントをキャンセル

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