とあるwebサービスでApp Storeの自動更新サブスクリプションを実装したのですが、
公式ドキュメントがわりと雑で、backend側を作るのがすごく大変だったのでまとめます
(Node.jsとfirebase Functionsを使用)
前提
この記事はiOSアプリ側の話ではなく、バックエンド側の話なので
レシートデータを取得できてからのお話になります
Sandboxのアカウントの作成、アプリ側の購入処理などについては
@Masataka-n様のどこよりもわかりやすいiOS最強課金まとめで分かりやすくまとめられているので参考にしてみてください
App Storeのサブスクリプションについて
サブスクリプションを実装する上で一番大事なものってなんでしょうか
それは、**『ユーザーが現在サブスクリプション購読中か否か』**を知ることです
そのためには、verifyReceiptとApp Store Server Notificationsの2つを理解する必要があります
また、重要なパラメータとしてApp Storeのレシート情報に含まれるoriginal transaction id
があります
これはApple IDと1対1で紐づいているIDで、
これを使用することでサービス内のユーザーを特定することができます
今回はverifyReceipt
を、次回でApp Store Server Notifications
を説明していきます
レシート検証API verifyReceipt
とりあえず持っているbase64エンコードされたくっっっっそ長いレシートデータをPostmanなどを使って
以下の通りjson形式で
https://sandbox.itunes.apple.com/verifyReceipt
へPOSTしてみましょう
{
"password": ***, // iOSアプリ側で設定済みのはず
"exclude-old-transactions": true,
"receipt-data": ******** //base64エンコードされたくっっっっそ長い文字列
}
返ってくる値はこんな感じです
{
"environment": "Sandbox",
"receipt": {
"receipt_type": "ProductionSandbox",
"adam_id": 0,
"app_item_id": 0,
"bundle_id": "***",
"application_version": "45",
"download_id": 0,
"version_external_identifier": 0,
"receipt_creation_date": "2020-10-13 01:48:13 Etc/GMT",
"receipt_creation_date_ms": "1602553693000",
"receipt_creation_date_pst": "2020-10-12 18:48:13 America/Los_Angeles",
"request_date": "2020-11-10 01:59:34 Etc/GMT",
"request_date_ms": "1604973574730",
"request_date_pst": "2020-11-09 17:59:34 America/Los_Angeles",
"original_purchase_date": "2013-08-01 07:00:00 Etc/GMT",
"original_purchase_date_ms": "1375340400000",
"original_purchase_date_pst": "2013-08-01 00:00:00 America/Los_Angeles",
"original_application_version": "1.0",
"in_app": [
{
"quantity": "1",
"product_id": "***",
"transaction_id": "1000000724743083",
"original_transaction_id": "1000000724743083",
"purchase_date": "2020-09-30 10:30:56 Etc/GMT",
"purchase_date_ms": "1601461856000",
"purchase_date_pst": "2020-09-30 03:30:56 America/Los_Angeles",
"original_purchase_date": "2020-09-30 10:30:58 Etc/GMT",
"original_purchase_date_ms": "1601461858000",
"original_purchase_date_pst": "2020-09-30 03:30:58 America/Los_Angeles",
"expires_date": "2020-09-30 10:35:56 Etc/GMT",
"expires_date_ms": "1601462156000",
"expires_date_pst": "2020-09-30 03:35:56 America/Los_Angeles",
"web_order_line_item_id": "1000000056115800",
"is_trial_period": "false",
"is_in_intro_offer_period": "false"
},
{
"quantity": "1",
"product_id": "***",
"transaction_id": "1000000724745717",
"original_transaction_id": "1000000724743083",
"purchase_date": "2020-09-30 10:35:56 Etc/GMT",
"purchase_date_ms": "1601462156000",
"purchase_date_pst": "2020-09-30 03:35:56 America/Los_Angeles",
"original_purchase_date": "2020-09-30 10:30:58 Etc/GMT",
"original_purchase_date_ms": "1601461858000",
"original_purchase_date_pst": "2020-09-30 03:30:58 America/Los_Angeles",
"expires_date": "2020-09-30 10:40:56 Etc/GMT",
"expires_date_ms": "1601462456000",
"expires_date_pst": "2020-09-30 03:40:56 America/Los_Angeles",
"web_order_line_item_id": "1000000056115801",
"is_trial_period": "false",
"is_in_intro_offer_period": "false"
},
..
]
},
"latest_receipt_info": [
{
"quantity": "1",
"product_id": "***",
"transaction_id": "1000000737669781",
"original_transaction_id": "1000000724743083",
"purchase_date": "2020-11-04 08:38:37 Etc/GMT",
"purchase_date_ms": "1604479117000",
"purchase_date_pst": "2020-11-04 00:38:37 America/Los_Angeles",
"original_purchase_date": "2020-11-04 08:37:58 Etc/GMT",
"original_purchase_date_ms": "1604479078000",
"original_purchase_date_pst": "2020-11-04 00:37:58 America/Los_Angeles",
"expires_date": "2020-11-04 08:43:37 Etc/GMT",
"expires_date_ms": "1604479417000",
"expires_date_pst": "2020-11-04 00:43:37 America/Los_Angeles",
"web_order_line_item_id": "1000000057023410",
"is_trial_period": "false",
"is_in_intro_offer_period": "false",
"subscription_group_identifier": "20664761"
}
],
"latest_receipt": "***", // めっちゃ長い
"pending_renewal_info": [
{
"expiration_intent": "1",
"auto_renew_product_id": "***",
"original_transaction_id": "1000000724743083",
"is_in_billing_retry_period": "0",
"product_id": "***",
"auto_renew_status": "0"
}
],
"status": 0
}
購読中かどうかを知りたいとき
項目多すぎてワケワカラン。
でも大丈夫。**『ユーザーが現在サブスクリプション購読中か否か』**を知りたい場合
latest_receipt_info
内のexpired_date
を見るだけです
既に期限切れであれば、latest_receipt_info
等についているoriginal_transaction_id
から該当のユーザーと照合し、
フラグを折る感じの実装になると思います
過去の購入履歴を知りたい
他にも、過去の購入履歴を見たいときはin_app
内からpurchase_date
とexpires_date
でフィルターをかけると取得できます
レシートデータの更新
リクエスト時に投げたreceipt-data
が古い場合は、
latest_receipt
で渡される値に更新しておきましょう
現在自動更新が有効かどうかを知りたい
ときは、pending_renewal_info
に含まれるauto_renew_status
を見ればOKです
1
ならば自動更新が有効で、0
ならば次回自動更新されないユーザーです
自動更新されない理由を知りたい
ときは、pending_renewal_info
に含まれるexpiration_intent
を見てください
月に一回cronでレシートデータをチェックして、1
のユーザーには訴求用のプッシュ通知を送る、
などの実装例が想像できますね
次回 Server Notifications
レシート検証APIはいかがだったでしょうか?
次回はApp Store Server Notifications
について説明していきます!