FURYU Tech Blog - フリュー株式会社

フリュー株式会社の開発者が技術情報を発信するブログです。

AppStore自動更新購読のレシートについて

こんにちは、コンテンツ・メディア第1事業部の前田です。

業務で自動更新購読型のAppStore課金を取り入れたのですが、AppStoreから返却される自動更新購読レシートの中身がよく分からず行き詰まることがありました。今回は自動更新購読レシートを調べた中で分かった仕様や消耗型・非消耗型レシートとの違い、ユーザの課金状態によってレシートの内容はどう変化するかについて書いていきます。

AppStore自動更新購読のざっくりとした流れ

上図が購入から完了までの流れになります。今回はレシートの内容についてなので詳細には触れません。

この図中にあるAppStoreAPIから返却された検証結果レシートの内容について詳しく見ていきます。

レシート仕様

AppStoreから返却されるレシート例を以下に示します。

レシートパラメータの各値は伏せ字にしておきます。見難いかと思いますがご了承下さい。

※レシートデータの内容はiOSのバージョン毎に異なりますので注意して下さい。

{
    "status": ■■■■■■, 
    "environment": "■■■■■■",
    "receipt": {
        "receipt_type": "■■■■■■",
        "adam_id": ■■■■■■,
        "app_item_id": ■■■■■■,
        "bundle_id": "■■■■■■",
        "application_version": "■■■■■■",
        "download_id": ■■■■■■,
        "version_external_identifier": ■■■■■■,
        "receipt_creation_date": "■■■■■■",
        "receipt_creation_date_ms": "■■■■■■",
        "receipt_creation_date_pst": "■■■■■■",
        "request_date": "■■■■■■",
        "request_date_ms": "■■■■■■",
        "request_date_pst": "■■■■■■",
        "original_purchase_date": "■■■■■■",
        "original_purchase_date_ms": "■■■■■■",
        "original_purchase_date_pst": "■■■■■■",
        "original_application_version": "■■■■■■",
        "in_app": [
            {
                "quantity": "■■■■■■",
                "product_id": "■■■■■■",
                "transaction_id": "■■■■■■",
                "original_transaction_id": "■■■■■■",
                "purchase_date": "■■■■■■",
                "purchase_date_ms": "■■■■■■",
                "purchase_date_pst": "■■■■■■",
                "original_purchase_date": "■■■■■■",
                "original_purchase_date_ms": "■■■■■■",
                "original_purchase_date_pst": "■■■■■■",
                "expires_date": "■■■■■■",
                "expires_date_ms": "■■■■■■",
                "expires_date_pst": "■■■■■■",
                "web_order_line_item_id": "■■■■■■",
                "is_trial_period": "■■■■■■"
            }
        ]
    },
    "latest_receipt_info": [
        {
            "quantity": "■■■■■■",
            "product_id": "■■■■■■",
            "transaction_id": "■■■■■■",
            "original_transaction_id": "■■■■■■",
            "purchase_date": "■■■■■■",
            "purchase_date_ms": "■■■■■■",
            "purchase_date_pst": "■■■■■■",
            "original_purchase_date": "■■■■■■",
            "original_purchase_date_ms": "■■■■■■",
            "original_purchase_date_pst": "■■■■■■",
            "expires_date": "■■■■■■",
            "expires_date_ms": "■■■■■■",
            "expires_date_pst": "■■■■■■",
            "web_order_line_item_id": "■■■■■■",
            "is_trial_period": "■■■■■■"
        },
        ・・・
    ],
    "latest_receipt": "■■■■■■■■■■■■■■■■■■・・・"
}

各パラメータ内容

重要なパラメータのみ説明します。

プロパティ 子プロパティ 内容
status レシートが正しければ0、異常であれば対応したエラーコードとなる。なお購読の有効期限が切れても0が返る。
receipt in_app latest_receiptの詳細となる。下記「in_app~消耗型・非消耗型プロダクトとの違い~」で詳しく説明。
latest_receipt_info 今まで購入した自動更新のレシートがすべて入る。下記「latest_receiptについて」で詳しく説明。
product_id なんの商品(たとえば1ヶ月購読と半年購読があったりした場合)を判別できるもの。
transaction_id 購入または更新に対するID。latest_receipt_infoの配列毎に値は異なる。
original_transaction_id product_idを購読購入したということに対するID。購読購入→一度やめる→また1年後に購入とした場合でも値は同じとなる。下記「original_transaction_idの検証で詳しく説明」
purchase_date transaction_idに対応した購読開始日時。
original_purchase_date transaction_idに対応した購読購入した日、または更新した日時。更新というのはApple側が更新をかけた日時であって、購読更新日(この日からまた購読)という日時ではない。
expires_date transaction_idに対応した購読期限。
cancellation_date Appleを通してキャンセルされた場合に入る。設定から自動更新オフした場合とかではない。ここに値が入っている場合は有効期限内であっても購入はキャンセルされているので注意。
latest_receipt 自動更新購読型にのみ存在する。アプリから渡され、レシートデータとしてAppStoreAPIへ渡す。ある購読情報をBase64エンコードしたもの。

in_appについて~消耗型・非消耗型プロダクトとの違い~

自動更新購読のレシート構造は消耗型・非消耗型プロダクト(ゲームなどによくあるアイテム課金等)のレシート構造といくつか違いがあります。非消耗型プロダクトのレシートは、in_appの中に課金したアイテムの情報が入ってきます。ですのでそのとき購入した情報はin_appを見れば分かるのですが、自動更新購読レシートはそうとは限りません。自動更新購読のin_appにはlatest_receiptに紐付く購入情報が入ってきます。latest_receiptが一番最新の購入情報であればin_appには最新の購入情報が入りますが、古いlatest_receiptであればin_appには古い購入情報が入ってきます。

具体的には下図のようになります。下図では自動更新購読の内容を「一ヶ月の定期購読課金」としています。

 

 latest_receipt_infoについて

latest_receipt_infoは一見すると最新のレシートのみが入ってくるようにみえるのですが、ここにはアプリ内で購入した自動更新のレシート情報が全て入ってきます。一度更新をやめてしばらく経ってから再度購読を開始した場合でも、以前の購読レシートは一緒になって返ってきます。また、アプリ内にプロダクトが複数あり(300円コース、1000円コース等)、かつ両方で課金したことがある場合には両方の情報が入ってきます(下図参照)。

original_transaction_idの検証

以下図にある3つの状態でレシートを取得した際、original_transaction_idの内容について検証した結果をまとめます。

ここでは、自動更新購読の内容を「一ヶ月の定期購読課金」としています。

 

①1月1日に購読を開始し、2月、3月も購読を更新している場合

latest_receipt_infoには3ヶ月分の購読情報が入ってくる。また、この3つのoriginal_transaction_idは全て同じものである。

 

②1月1日に購読を開始。1月5日に自動更新を解除したが、1月10日に更新解除をやめ、2月、3月と購読した場合

latest_receipt_infoには3ヶ月分の購読情報が入ってくる。また、この3つのoriginal_transaction_idは全て同じものである。

 

③1月1日に購読を開始し、1月5日に自動更新を解除。3月1日に購読を開始した場合。

latest_receipt_infoには1月、3月の購読情報が入ってくる。また、この2つのoriginal_transaction_idは全て同じものである。

 

つまり、あるアプリ内で自動購読を開始すると、途中で更新解除→再度課金してもoriginal_transaction_idは全て同じとなります。じゃあどこで月々の購読情報を見分けるの?と言うと、transaction_idで見分けることができます。パラメータ内容にも書きましたが、transaction_idには購読が更新される毎に違う値が入ってくるからです。

感想

初めはレシートの中身がややこしすぎて全く分からない…と焦っていたのですが、実際に取得したSandboxのレシートを見てみることによって仕組みを理解することができました。今後自動更新購読を実装する際に参考になればと思います。

参考

In-App Purchaseプログラミングガイド

レシート検証プログラミングガイド

自動購読課金について【iOS編】- サイバーエージェント 公式エンジニアブログ

商標について

AppStore、In-App Purchaseは、Apple Inc.の商標です。