appleの Server to Server Notifications に関する注意点


Apple の Server-to-Serve Notification の仕様への不安

実際に調査して実装し、本番環境で受け取った通知の内容を確認して思うことは、appleのin-app purchaseに関わる仕様が理解しにくいということです。
今回は私が実際に直面した問題に関して、後のためにメモしておきます。

仕様の違う environment パラメーター

Server-to-Server Notifications はルート直下とunified_receipt直下にenvironmentというパラメータを返します。
このパラメーターは、本番環境では入る値が違います。
それぞれの説明は以下です。

ルート直下

The environment for which the receipt was generated.
Possible values: Sandbox, PROD

unified_receipt直下

The environment for which the receipt was generated.
Possible values: Sandbox, Production

ルート直下はPRODを返し、unified_receipt直下はProductionを返します。

開発環境では DID_FAIL_TO_RENEW のテストが不可能

開発環境で通知が来る Notification Type は以下の物のみです。

  • INITIAL_BUY(テストアカウント毎に一度だけ)
  • DID_CHANGE_RENEWAL_PREF
  • DID_CHANGE_RENEWAL_STATUS
  • DID_RECOVER
  • INTERACTIVE_RENEWAL

課金に失敗してサブスクリプションの自動更新に失敗する際の通知である DID_FAIL_TO_RENEW は、課金が失敗するようにする設定画面が存在しないため、開発環境ではテストができません。

(iOS14からテストができるようになるとのことですが、2020-08-10現在まだリリースされていません。)

この部分は推測で実装するしかなく、本番環境で想定通りのパラメーターが渡っているかを、ログを仕込んで様子をみる必要があります。

サブスクリプションの自動更新時に通知は来ない(将来的には来るようになります)

現時点では、サブスクリプションの自動更新時に通知は来ません。
自動更新されたかどうかは verifyReceipt のAPIでサブスクリプションステータスをPollingしてくれと言っています。(ここの34:30あたり)

iOS14からは DID_RENEW 通知が追加されますので、StatusPollingをする必要性は理論上は無くなります。
が、引き続き(念のため)StatusPollingは実装しておいてくれと言っています。

「サブスクリプションを解約する」という状態は存在しない。 original_transaction_id は引き継がれる。

appleではサブスクリプションの解約という状態は存在せず「自動更新の停止」という状態を「解約」と表現しています

そのため、サブスクリプションを一意に識別するoriginal_transaction_idは、サブスクリプションを「解約」しても、再度サブスクリプションを購入した場合、同じ値が引き継がれます。
「解約→再加入」ではなく「停止→再開」という意味合いになります。
(ちなみにgoogleでは「解約→再加入」という仕様なので、サブスクリプションの識別子はそれぞれ違う物が振られます。)

継続課金失敗時の挙動。2ヶ月間の課金リトライと、自動更新の停止。

自動更新の停止は以下の2パターンで起き得ます。
1. ユーザーが画面から設定する、意図的な解約
2. 継続時の課金失敗を原因とする、ユーザーの意図していない解約

この2番目について、課金のリトライを1度目の失敗と同時刻に、2ヶ月間行います。

ユーザーの支払い方法が更新されていれば、更新後のリトライ時点でDID_RECOVER通知と共にサブスクリプションが再開されます。

2ヶ月間の内に支払い方法が更新されない場合、1度目の失敗から2ヶ月経過した日に、DID_CHANGE_RENEWAL_STATUS の通知と共に、「自動更新を停止」します。
「自動解約」という状態は存在しません。

original_transaction_id が変わる場合は、「購入履歴を復元」した場合

「購入履歴を復元」した場合は original_transaction_id が変わります。
正確に言えば、復元をするとreceipt履歴が2つに割れます。復元によってできた履歴にはoriginal_transaction_idが新たに振られ今後更新されます。復元前の履歴は更新が止まります。

この記事について、今後

上記は、挙動の把握に間違いがあるかもしれませんので、実際の挙動はご確認ください。
気づいた点は引き続き追記していきます。