この記事は、「モバイルのサブスクリプションのアーキテクチャ」の参考記事になります。
App Store Server Notificationを実装し運用しているので、その中で得た知見を記載していきます。
実現することは、「iOSアプリの最新の定期購読レシート情報を、サービスのサーバーに常に保持しておくということ」です。
App Store Server Notificationとは
App Store Server Notificationとは、定期購読のステータスの変更及び更新が行われる度に、事前に指定したエンドポイントにHTTP POSTによりJSONを飛ばしてくるサービスです。
送られてくるJSONは以下の公式ドキュメントをご確認ください。
[Apple Developer Documentation]
この送られてくるJSON無いの最上位層にある
”unified_receipt > latest_receipt_info”
の情報を用いて、サーバー内のレシート情報を更新することになります。
送られてくるJSONの中には様々な情報があり、最上位層には”latest_receipt”等も含まれています。しかしこちらは公式ドキュメントによると、depricatedなようなので使用せず、unified_receiptのデータを使う必要があります。
App Store Server Notification の設定方法
Apple Developer ProgramからApplicationを開き、左側メニューの 一般 > App情報に進みます。
中段にApp Storeサーバー通知のURLという欄があるので、そこにPOSTを受け取るエンドポイントを指定します。
これでApp Storeでの設定は完了です。これだけです。
App Store Server Notificationで受け取ったデータで、サーバー内に保管しているレシートデータを更新する
サブスクリプションを一意に特定するには、レシートの
”original_transaction_id”
を使用します。(string型のデータです、)
以下は、Ruby on Railsでの例です。
def XXXXXX
unified_receipt = params['unified_receipt'].as_json
latest_receipt = unified_receipt['latest_receipt']
latest_receipt_info = unified_receipt['latest_receipt_info']
not_expired_info = latest_receipt_info.select{ |e|
e['expires_date_ms'].to_i / 1000 > Time.zone.now.to_i
}.first
...
# 受領データ保管処理
...
log = LogTable.where(original_transaction_id: not_expired_info['original_transaction_id']).first
...
if not_expired_info['product_id'] != 'PRODUCT ID'
return
end
# レシートの有効期限を更新
log.update!(expire_date: not_expired_info['expires_date_ms'].to_i / 1000)
end
ポイントは以下の3点です。
- 受け取ったらとりあえず問答無用でログを保管する
- unified_receipt > latest_receipt_info に格納されているものを使用する
- original_transaction_idでアップデート対象のレシートを判別する
これにより、サービスのサーバー側で最新のレシート情報で有効期限を更新するこができるようになりました。
実装途中でつまずいた点
Sandbox環境での実装でサブスクリプションをテスト実装すると、更新は5度行われて解約する処理になるといった記述が公式ドキュメントにはあるのですが、実際には3回ほどで解約処理されてしまい、原因追求にかなり時間をかけてしまいました。
無視して本番環境で運用していますが、2020年11月現在、問題なく動作しています。
ググってみると、Sandbox環境は不安定だとか色々見つかるので、まあ一旦やってみるか、と思ってやってみて、とりあえず大丈夫そうです。
参考になりましたら幸いです。
参考URL