先日のAppleの発表により、月額課金を適用できるアプリの範囲拡大や利益配分の変更などが発表されました。
これから月額課金を実装するアプリが増えていくと予想されますが、Appleの課金の仕様はかなり複雑であり、ドキュメントを読んだだけで理解できない部分もあります。
そこで、今回は本番(Production)環境で取得できるレシートをまとめて、今後課金を実装する人の助けになればと思い書かせていただきます。
今回の記事ではアプリ内で取得したレシートデータをAppleのサーバに送信し、返答のjsonを一部改変(アプリ固有の情報を削除)した物をまとめていきます。
課金の実装にあたってはCyberAgentEngineerBlogを参考にさせていただきました。
レシートの有効期限やSandBox環境等の情報は今回の記事では扱いませんので、上記のブログを参考にしてください。
記事対象
今回記載するデータはiOS7以降、具体的に以下のコードで取得できるデータを取り扱います。
NSBundle.mainBundle().appStoreReceiptURL
未課金時
AppStoreにリリースされているアプリでは、課金アイテムがない場合も appStoreReceiptURL
にレシートが存在します。
{
"status": 0,
"environment": "Production",
"receipt": {
"receipt_type": "Production",
"adam_id": 0,
"app_item_id": 0,
"bundle_id": "bundle_id",
"application_version": "1.0",
"download_id": 0,
"version_external_identifier": 0,
"receipt_creation_date": "2016-02-18 12:15:48 Etc/GMT",
"receipt_creation_date_ms": "1455797748000",
"receipt_creation_date_pst": "2016-02-18 04:15:48 America/Los_Angeles",
"request_date": "2016-02-18 13:05:37 Etc/GMT",
"request_date_ms": "1455800737074",
"request_date_pst": "2016-02-18 05:05:37 America/Los_Angeles",
"original_purchase_date": "2016-02-18 09:12:43 Etc/GMT",
"original_purchase_date_ms": "1455786763000",
"original_purchase_date_pst": "2016-02-18 01:12:43 America/Los_Angeles",
"original_application_version": "1.0",
"in_app": []
}
}
未課金状態では、レシートの大元データのみが存在し、初回にレシートが作成された日付やbundle_id
、アプリケーションバージョンなどが格納されています。
課金開始時
初めて月額課金を開始した後のレシートは以下のような形となります。
{
"status": 0,
"environment": "Production",
"receipt": {
"receipt_type": "Production",
"adam_id": 0,
"app_item_id": 0,
"bundle_id": "bundle_id",
"application_version": "1.0",
"download_id": 0,
"version_external_identifier": 0,
"receipt_creation_date": "2016-02-18 13:08:26 Etc/GMT",
"receipt_creation_date_ms": "1455800906000",
"receipt_creation_date_pst": "2016-02-18 05:08:26 America/Los_Angeles",
"request_date": "2016-02-18 13:08:26 Etc/GMT",
"request_date_ms": "1455800906898",
"request_date_pst": "2016-02-18 05:08:26 America/Los_Angeles",
"original_purchase_date": "2016-02-18 09:12:43 Etc/GMT",
"original_purchase_date_ms": "1455786763000",
"original_purchase_date_pst": "2016-02-18 01:12:43 America/Los_Angeles",
"original_application_version": "1.0",
"in_app": [
{
"quantity": "1",
"product_id": "product_id",
"transaction_id": "0",
"original_transaction_id": "0",
"purchase_date": "2016-02-18 13:08:25 Etc/GMT",
"purchase_date_ms": "1455800905000",
"purchase_date_pst": "2016-02-18 05:08:25 America/Los_Angeles",
"original_purchase_date": "2016-02-18 13:08:25 Etc/GMT",
"original_purchase_date_ms": "1455800905000",
"original_purchase_date_pst": "2016-02-18 05:08:25 America/Los_Angeles",
"expires_date": "2016-03-18 12:08:25 Etc/GMT",
"expires_date_ms": "1458302905000",
"expires_date_pst": "2016-03-18 05:08:25 America/Los_Angeles",
"web_order_line_item_id": "0",
"is_trial_period": "false"
}
]
},
"latest_receipt_info": [
{
"quantity": "1",
"product_id": "product_id",
"transaction_id": "0",
"original_transaction_id": "0",
"purchase_date": "2016-02-18 13:08:25 Etc/GMT",
"purchase_date_ms": "1455800905489",
"purchase_date_pst": "2016-02-18 05:08:25 America/Los_Angeles",
"original_purchase_date": "2016-02-18 13:08:25 Etc/GMT",
"original_purchase_date_ms": "1455800905000",
"original_purchase_date_pst": "2016-02-18 05:08:25 America/Los_Angeles",
"expires_date": "2016-03-18 12:08:25 Etc/GMT",
"expires_date_ms": "1458302905489",
"expires_date_pst": "2016-03-18 05:08:25 America/Los_Angeles",
"web_order_line_item_id": "0",
"is_trial_period": "false"
}
],
"latest_receipt": "base_64_latest_receipt"
}
課金状態になるとin_app
とlatest_receipt_info
にレシート情報が記載されます。
また、latest_receipt
には最新のレシートがbase64文字列で格納されています。
ここで、注意しなければいけないのは、latest_receipt_info
とin_app
は同階層にいないことです。
課金後にアプリを削除し、リストア処理
一度アプリを削除し、リストアを行いレシートを復元させた場合は以下のような形となります。
{
"status": 0,
"environment": "Production",
"receipt": {
"receipt_type": "Production",
"adam_id": 0,
"app_item_id": 0,
"bundle_id": "bundle_id",
"application_version": "1.0",
"download_id": 0,
"version_external_identifier": 0,
"receipt_creation_date": "2016-02-18 13:29:12 Etc/GMT",
"receipt_creation_date_ms": "1455802152000",
"receipt_creation_date_pst": "2016-02-18 05:29:12 America/Los_Angeles",
"request_date": "2016-02-18 13:29:13 Etc/GMT",
"request_date_ms": "1455802153032",
"request_date_pst": "2016-02-18 05:29:13 America/Los_Angeles",
"original_purchase_date": "2016-02-18 09:12:43 Etc/GMT",
"original_purchase_date_ms": "1455786763000",
"original_purchase_date_pst": "2016-02-18 01:12:43 America/Los_Angeles",
"original_application_version": "1.0",
"in_app": [
{
"quantity": "1",
"product_id": "product_id",
"transaction_id": "0",
"original_transaction_id": "0",
"purchase_date": "2016-02-18 13:08:25 Etc/GMT",
"purchase_date_ms": "1455800905000",
"purchase_date_pst": "2016-02-18 05:08:25 America/Los_Angeles",
"original_purchase_date": "2016-02-18 13:08:25 Etc/GMT",
"original_purchase_date_ms": "1455800905000",
"original_purchase_date_pst": "2016-02-18 05:08:25 America/Los_Angeles",
"expires_date": "2016-03-18 12:08:25 Etc/GMT",
"expires_date_ms": "1458302905000",
"expires_date_pst": "2016-03-18 05:08:25 America/Los_Angeles",
"web_order_line_item_id": "0",
"is_trial_period": "false"
}
]
},
"latest_receipt_info": [
{
"quantity": "1",
"product_id": "product_id",
"transaction_id": "0",
"original_transaction_id": "0",
"purchase_date": "2016-02-18 13:08:25 Etc/GMT",
"purchase_date_ms": "1455800905489",
"purchase_date_pst": "2016-02-18 05:08:25 America/Los_Angeles",
"original_purchase_date": "2016-02-18 13:08:25 Etc/GMT",
"original_purchase_date_ms": "1455800905000",
"original_purchase_date_pst": "2016-02-18 05:08:25 America/Los_Angeles",
"expires_date": "2016-03-18 12:08:25 Etc/GMT",
"expires_date_ms": "1458302905489",
"expires_date_pst": "2016-03-18 05:08:25 America/Los_Angeles",
"web_order_line_item_id": "0",
"is_trial_period": "false"
}
],
"latest_receipt": "base_64_latest_receipt"
}
データの違いはレシートの作成日やlatest_receipt
の値が変更されたのみで課金情報等はかわりありませんでした。
自動更新があった後に古いレシートをAppleに送信
今までの情報はweb上で検索すればいくつか見ることができましたが、継続課金が一度でも行われた後のレシートの情報はあまりありませんでした。
今回は初回課金のレシートをサーバ側に保持しておき、そのデータをそのまま継続課金後(1ヶ月後)にAppleに送信して得られたレシート情報を記載します。
この時、継続課金が行われたアプリは初回の課金状態から一度も起動を行わずレシートの更新処理などもまったく行っていません。
{
"status": 0,
"environment": "Production",
"receipt": {
"receipt_type": "Production",
"adam_id": 0,
"app_item_id": 0,
"bundle_id": "bundle_id",
"application_version": "1.0",
"download_id": 0,
"version_external_identifier": 0,
"receipt_creation_date": "2016-02-18 13:29:12 Etc/GMT",
"receipt_creation_date_ms": "1455802152000",
"receipt_creation_date_pst": "2016-02-18 05:29:12 America/Los_Angeles",
"request_date": "2016-03-22 08:35:07 Etc/GMT",
"request_date_ms": "1458635707217",
"request_date_pst": "2016-03-22 01:35:07 America/Los_Angeles",
"original_purchase_date": "2016-02-18 09:12:43 Etc/GMT",
"original_purchase_date_ms": "1455786763000",
"original_purchase_date_pst": "2016-02-18 01:12:43 America/Los_Angeles",
"original_application_version": "1.0",
"in_app": [
{
"quantity": "1",
"product_id": "product_id",
"transaction_id": "0",
"original_transaction_id": "0",
"purchase_date": "2016-02-18 13:08:25 Etc/GMT",
"purchase_date_ms": "1455800905000",
"purchase_date_pst": "2016-02-18 05:08:25 America/Los_Angeles",
"original_purchase_date": "2016-02-18 13:08:25 Etc/GMT",
"original_purchase_date_ms": "1455800905000",
"original_purchase_date_pst": "2016-02-18 05:08:25 America/Los_Angeles",
"expires_date": "2016-03-18 12:08:25 Etc/GMT",
"expires_date_ms": "1458302905000",
"expires_date_pst": "2016-03-18 05:08:25 America/Los_Angeles",
"web_order_line_item_id": "0",
"is_trial_period": "false"
}
]
},
"latest_receipt_info": [
{
"quantity": "1",
"product_id": "product_id",
"transaction_id": "0",
"original_transaction_id": "0",
"purchase_date": "2016-02-18 13:08:25 Etc/GMT",
"purchase_date_ms": "1455800905489",
"purchase_date_pst": "2016-02-18 05:08:25 America/Los_Angeles",
"original_purchase_date": "2016-02-18 13:08:25 Etc/GMT ",
"original_purchase_date_ms": "1455800905000",
"original_purchase_date_pst": "2016-02-18 05:08:25 America/Los_Angeles",
"expires_date": "2016-03-18 12:08:25 Etc/GMT",
"expires_date_ms": "1458302905489",
"expires_date_pst": "2016-03-18 05:08:25 America/Los_Angeles",
"web_order_line_item_id": "0",
"is_trial_period": "false"
},
{
"quantity": "1",
"product_id": "product_id",
"transaction_id": "0",
"original_transaction_id": "0",
"purchase_date": "2016-03-18 12:08:25 Etc/GMT",
"purchase_date_ms": "1458302905000",
"purchase_date_pst": "2016-03-18 05:08:25 America/Los_Angeles",
"original_purchase_date": "2016-03-18 06:08:31 Etc/GMT",
"original_purchase_date_ms": "1458281311702",
"original_purchase_date_pst": "2016-03-17 23:08:31 America/Los_Angeles",
"expires_date": "2016-04-18 12:08:25 Etc/GMT",
"expires_date_ms": "1460981305000",
"expires_date_pst": "2016-04-18 05:08:25 America/Los_Angeles",
"web_order_line_item_id": "0",
"is_trial_period": "false"
}
],
"latest_receipt": "base_64_latest_receipt"
}
レシートデータの中は、latest_receipt_info
の中に更新後のレシートが入っていることがわかります。
この情報を元に継続課金が行われているかどうかの判定を行えばよさそうです。
in_app
の中はレシートはそのままなのがわかります。
これは、base64が作成された時点でアプリ内に入っているレシートが格納されているため、初回のレシートを投げると初回の状態のままのin_app
が返答されます。
また、課金開始時
のjson内のlatest_receipt
のbase64文字列をこのタイミングでAppleに送信しても同様の結果を得られます。
アプリを起動し、最新のレシートをAppleに送信
継続課金後にアプリを起動し、取得できた最新のレシートを送信すると以下のjsonが得られます。
{
"status": 0,
"environment": "Production",
"receipt": {
"receipt_type": "Production",
"adam_id": 0,
"app_item_id": 0,
"bundle_id": "bundle_id",
"application_version": "1.0",
"download_id": 0,
"version_external_identifier": 0,
"receipt_creation_date": "2016-03-22 08:45:28 Etc/GMT",
"receipt_creation_date_ms": "1458636328000",
"receipt_creation_date_pst": "2016-03-22 01:45:28 America/Los_Angeles",
"request_date": "2016-03-22 08:46:44 Etc/GMT",
"request_date_ms": "1458636404704",
"request_date_pst": "2016-03-22 01:46:44 America/Los_Angeles",
"original_purchase_date": "2016-02-18 09:12:43 Etc/GMT",
"original_purchase_date_ms": "1455786763000",
"original_purchase_date_pst": "2016-02-18 01:12:43 America/Los_Angeles",
"original_application_version": "1.0",
"in_app": [
{
"quantity": "1",
"product_id": "product_id",
"transaction_id": "0",
"original_transaction_id": "0",
"purchase_date": "2016-02-18 13:08:25 Etc/GMT",
"purchase_date_ms": "1455800905000",
"purchase_date_pst": "2016-02-18 05:08:25 America/Los_Angeles",
"original_purchase_date": "2016-02-18 13:08:25 Etc/GMT",
"original_purchase_date_ms": "1455800905000",
"original_purchase_date_pst": "2016-02-18 05:08:25 America/Los_Angeles",
"expires_date": "2016-03-18 12:08:25 Etc/GMT",
"expires_date_ms": "1458302905000",
"expires_date_pst": "2016-03-18 05:08:25 America/Los_Angeles",
"web_order_line_item_id": "0",
"is_trial_period": "false"
},
{
"quantity": "1",
"product_id": "product_id",
"transaction_id": "0",
"original_transaction_id": "0",
"purchase_date": "2016-03-18 12:08:25 Etc/GMT",
"purchase_date_ms": "1458302905000",
"purchase_date_pst": "2016-03-18 05:08:25 America/Los_Angeles",
"original_purchase_date": "2016-03-18 06:08:31 Etc/GMT",
"original_purchase_date_ms": "1458281311000",
"original_purchase_date_pst": "2016-03-17 23:08:31 America/Los_Angeles",
"expires_date": "2016-04-18 12:08:25 Etc/GMT",
"expires_date_ms": "1460981305000",
"expires_date_pst": "2016-04-18 05:08:25 America/Los_Angeles",
"web_order_line_item_id": "0",
"is_trial_period": "false"
}
]
},
"latest_receipt_info": [
{
"quantity": "1",
"product_id": "product_id",
"transaction_id": "0",
"original_transaction_id": "0",
"purchase_date": "2016-02-18 13:08:25 Etc/GMT",
"purchase_date_ms": "1455800905489",
"purchase_date_pst": "2016-02-18 05:08:25 America/Los_Angeles",
"original_purchase_date": "2016-02-18 13:08:25 Etc/GMT",
"original_purchase_date_ms": "1455800905000",
"original_purchase_date_pst": "2016-02-18 05:08:25 America/Los_Angeles",
"expires_date": "2016-03-18 12:08:25 Etc/GMT",
"expires_date_ms": "1458302905489",
"expires_date_pst": "2016-03-18 05:08:25 America/Los_Angeles",
"web_order_line_item_id": "0",
"is_trial_period": "false"
},
{
"quantity": "1",
"product_id": "product_id",
"transaction_id": "0",
"original_transaction_id": "0",
"purchase_date": "2016-03-18 12:08:25 Etc/GMT",
"purchase_date_ms": "1458302905000",
"purchase_date_pst": "2016-03-18 05:08:25 America/Los_Angeles",
"original_purchase_date": "2016-03-18 06:08:31 Etc/GMT",
"original_purchase_date_ms": "1458281311702",
"original_purchase_date_pst": "2016-03-17 23:08:31 America/Los_Angeles",
"expires_date": "2016-04-18 12:08:25 Etc/GMT",
"expires_date_ms": "1460981305000",
"expires_date_pst": "2016-04-18 05:08:25 America/Los_Angeles",
"web_order_line_item_id": "0",
"is_trial_period": "false"
}
],
"latest_receipt": "base_64_latest_receipt"
}
アプリ内のデータも更新されているレシートのため、in_app
の中のレシートも2個になっています。
まとめ
今回はただ、appleから返答されているデータをまとめただけですが、実際に運用されているProduction環境のレシートの例は少なく、継続課金時の判定に参考になるかと思います。
願わくばこの検証を行うためにApple様に捧げた実費が今後の課金機能実装者の助けになれば幸いです。