[iOS:Reading docs] Restoring Purchased Products

zombie caffe
11 min readNov 15, 2020
Photo by Isaac Quick on Unsplash

忙しい人のための公式ドキュメント要約記事です。

対象ドキュメント

Restoring Purchased Products

どんなドキュメント?

Apple API Documentに含まれている、IAP(In App Purchase)のリストア処理の実装について説明されています。StoreKit APIドキュメントだけではどう扱えばよいのかいまいちわかりにくいので、実装前に一読する価値ありです。

要点

このドキュメントに書かれている要点は、以下の通りです。

  • ユーザがiPhoneを機種変更した時などに備えて、リストア機能を提供すべし
  • リストアを自動的にやってはいけない(AppStoreの認証がアプリのフローに割り込むため)
  • 大半のケースでは、レシートをリフレッシュして、レシート内にリストされているプロダクトを配信するだけでOK (つまり、リストア前に、まずレシートのリフレッシュが必要と読み取れる)
  • applicationUsername については、プロパティとして指定可能なことは書かれているが、これによってどうなるかは書かれていない
  • original_transaction_id フィールドと、 original_purchase_date 、 purchase_date フィールドを参照すべし
  • Appleサーバに課金コンテンツをホストしている場合、トランザクションを完了させる前に、コンテンツのダウンロードを完了させよう
  • リストア対象が複数ある場合、全てをリストアするのではなく、ユーザに選択させるべし
  • Appレシートを使わないならば、リストアされた完了済みの全てのトランザクションを検査する と書いてある (裏返すと、アプリレシートを使うならばリストアされた全てのトランザクションを検査する必要はないということが読み取れる。)

以下に、いくつか内容を引用しつつ補足します。

リストアしたトランザクションを即座に終了させてよいケースについて

StoreKit は、トランザクションキューのオブザーバを呼び出す。各々のリストアされたトランザクションについて、 SKPaymentTransactionState.restored ステータスで。 Processing a Transaction の項で説明したように。

そのアクションは、あなたのアプリデザインに合わせて、実行するタイミングは依存している。

もし、あなたのアプリがAppレシートを使っていて、Appleサーバにコンテンツをホストしていないならば、このコードは不要です。なぜなら、あなたのアプリは、完了したトランザクションをリストアする必要がないため。即座にいかなるリストアしたトランザクションも終了させましょう。

Appレシート使っていてAppleサーバにコンテンツをホスト等していない場合は、リストアしたトランザクションを即座に終了させてOKと言っています。

リストア時に考慮が必要なケースについて

多くのケースでは、 Appレシートをリフレッシュしてそのレシートにリストされているプロダクトを配信するだけだが、以下のケースでは、別のアプローチが必要になると言っています。

- You use Apple-hosted content — Restore completed transactions to give your app the transaction objects it uses to download the content.

- You need to support your app on devices where the app receipt isn’t available — Restore completed transactions instead.

- Your app uses non-renewing subscriptions — Your app is responsible for the restoration process.

- あなたはAppleサーバにホストされたコンテンツを利用している場合 — 完了したトランザクションをリストアして、あなたのアプリへトランザクションオブジェクトを渡しましょう。それは、コンテンツのダウンロードに利用されます。

- あなたは、Appレシートを利用できないアプリをあなたのアプリでサポートする必要がある場合 — 代わりに完了したトランザクションをリストアする。

- あなたのアプリは更新のない購読を利用する場合 — あなたのアプリは、リストアのプロセスの責任を持つ必要がある。

1点目は、先程の繰り返しになります。

2点目は、「Appレシートを利用できないアプリ」というのが何を指しているのかわかりませんが、マルチプラットフォームで展開しているサービスのiOS以外のアプリなどでしょうか?

3点目は、non-renewing な購読についてです。

Appレシートのリフレッシュについて

レシートのリフレッシュについても説明されています。

Refreshing a receipt doesn’t create new transactions; it requests the latest copy of the receipt from the App Store. Refresh the receipt only once; refreshing multiple times in a row has the same result.

レシートのリフレッシュは新しいトランザクションを生成しない;それはリスエストする最新のレシートのコピーをAppStoreから。

リフレッシュは一度だけにしましょう;1つのデータに対して、複数回のリフレッシュは同じ結果を返します。

Refresh the App Receipt

Create a receipt refresh request, set a delegate, and start the request. The request supports optional properties for obtaining receipts in various states, such as expired receipts, during testing. For details, see the init(receiptProperties:)method of SKReceiptRefreshRequest.

レシートをリフレッシュするリクエストを作成しましょう。デリゲートをセットして、リクエストを開始しましょう。

そのリクエストは、オプショナルなプロパティをサポートしている。様々な状態のレシートを得るための。テスト中の期限切れレシートなど。

詳細は、SKReceiptRefreshRequestinit(receiptProperties:) メソッドをご覧ください。

After the app receipt is refreshed, examine it and deliver any products that were added to the receipt.

Appレシートがリフレッシュされた後、そのレシートに追加されたプロダクトを検査して配信しましょう。

リフレッシュをどのようなケースでやるべきかについて、ここには明記されていません。これについては、後述します。

なお、オプショナルなプロパティについては、以下のように書いてあります。

https://developer.apple.com/documentation/storekit/skreceiptrefreshrequest/1506038-init

In the test environment, the properties that the new receipt should have. For keys, see Receipt Property Keys.

In the production environment, set this parameter to nil.

プロダクション環境では、nilをセットすべし、テスト環境では、用意されているいくつかのキーをセットすることができる、ということのようです。

applicationUernameプロパティについて

リストアを実行する際に、このプロパティが指定できると言っています。しかし、このプロパティについての詳細な説明が見当たりません。

Restore Completed Transactions

Your app starts restoring completed transactions by calling the restoreCompletedTransactions() method of SKPaymentQueue. This call sends a request to the App Store to restore all of your app’s completed transactions. If your app sets a value for the applicationUsername property of its payment requests, use the restoreCompletedTransactions(withApplicationUsername:) method to provide the same information when restoring the transactions.

完了したトランザクションのリストア

SKPaymentQueuerestoreCompletedTransactions()メソッドによって、あなたのアプリは、完了したトランザクションのリストアを開始する。

この呼び出しは、AppStoreへあなたのアプリの完了したトランザクションの全てをリストアするためのリクエストを送信する。

もし、あなたのアプリがその課金リクエストのapplicationUsername値をセットするならば、restoreCompletedTransactions(withApplicationUsername:) メソッドを使いましょう。そのトランザクションがリストアされる時と同じ情報を提供するために。

Appレシートを使わない場合

Appレシートを使わないケースについても言及されています。Appレシートを使わないというのは、おそらく、iOS6タイプのレシートで処理することを指していると思われます。

If your app doesn’t use the app receipt, it examines all completed transactions as they’re restored.

もし、あなたのアプリが、Appレシートを使わないならば、リストアされた全ての完了したトランザクションを検査します。

結局、Appレシートのリフレッシュはいつやるべき?

このドキュメントにはレシートのリフレッシュが必要なケースが明記されていませんが、SKReceiptRefreshReqeustのAPIドキュメントによると、

https://developer.apple.com/documentation/storekit/skreceiptrefreshrequest

Use this API to request a new receipt if the receipt is invalid or missing. In the sandbox environment, you can request a receipt with any combination of properties to test the state transitions related to Volume Purchase Plan receipts.

「Appレシートが無効な場合や存在しない場合」と書かれています。

存在しない場合はベリファイができないし、ベリファイしないと無効かどうかも判断つかないので、つまり、リストア処理を行う前に必ずリフレッシュするというのが安全ではないかと思われます。

(そのように実装している記事や、Ask to Buy の際にAppレシートが存在せず、リフレッシュが必要という記事も見かけました。 )

おわりに

このドキュメントを読むことで、IAPのリストア処理をどう実装すればよいか、その概要が見えてきました。

applicationUsernameパラメータについては、それを指定することで何が起こるのかといったことがここからは読み取れなかったので、また調べてみたいと思います。

--

--