StoreKit 2サーバーAPIについての新機能


アップルは、最近起こったWWDC 2021の間、StoreKit 2の新しいバージョンを持ち出しました.これは、IOSでの購入を行うためのフレームワークです.アプリの購入とサブスクリプションの機能を持つアプリケーションの共有は着実に成長し、Appleは大幅にApp Storeのアプリケーションの購入をStoreKit 2をリリースして統合を簡素化.今日、我々はApp StoreのサーバーAPIの助けを借りて、サーバーの一部、つまり言い換えれば、StoreKit 2と共に働くことを考えます.

認証を要求する


現在のAPIバージョンでは、要求を送信するために共有秘密が必要です.これは、App Storeの接続で得ることができる秘密の固定文字列です.APIの新しいバージョンは、要求認証のためのJSONウェブトークン(JWT)標準を使用します.

キージェネレーション


まず第一にcreate a private key これはリクエストを承認するために使用されます.オープンApp Storeに接続し、ユーザーとアクセスセクション、キーキーに移動します.アプリ内購入キータイプで選択します.新しいキーをダウンロードします.また、そのIDが必要になります-あなたはApp Store Connect APIタブで見つけることができる問題IDと同じページにそれをコピーすることができます.
アプリケーションストアサーバーAPIでの作業のための秘密キーの作成

トークンの作成


次のステップは、リクエストを承認するために使用するトークンを作成することです.このプロセスを詳細に説明するdocumentation , だからあまりにも多くの注意を払う理由はありません.Python用の既製の実装例です.新しいリクエストのために新しいトークンを生成するのは全く意味がないことに注意してください.トークンを作成するときは、その期間を最高60分で設定し、この期間に同じトークンを使用します.
import time, uuid
from authlib.jose import jwt

BUNDLE_ID = 'com.adapty.sample_app'
ISSUER_ID = '4336a124-f214-4d40-883b-6db275b5e4aa'
KEY_ID = 'J65UYBDA74'
PRIVATE_KEY = '''
-----BEGIN PRIVATE KEY-----
MIGTAgMGByqGSMBHkAQQgR/fR+3Lkg4...
-----END PRIVATE KEY-----
'''

issue_time = round(time.time())
expiration_time = issue_time + 60 * 60 # 1 hour expiration


header = {
 'alg': 'ES256',
 'kid': KEY_ID,
 'typ': 'JWT'
}

payload = {
 'iss': ISSUER_ID,
 'iat': issue_time,
 'exp': expiration_time,
 'aud': 'appstoreconnect-v1',
 'nonce': str(uuid.uuid4()),
 'bid': BUNDLE_ID
}

token_encoded = jwt.encode(header, payload, PRIVATE_KEY)
token_decoded = token_encoded.decode()

authorization_header = {
 'Authorization': f'Bearer {token_decoded}'
}

署名取引


APIの新しいバージョンでは、JSONウェブ署名(JWS)標準で返されるすべてのトランザクション.これはドットで区切られた3つの部分からなる文字列です.
  • base 64ヘッダ
  • Base 64トランザクションペイロード.
  • トランザクション署名.
  • Base64(header) + "." + Base64(payload) + "." + sign(Base64(header) + "." + Base64(payload))

    トランザクションヘッダ


    ヘッダーは、トランザクションが本物であることを確認するために必要です.Alg キーは暗号化アルゴリズムを含みます.x5c キーは証明書チェーンを含んでいます.
    {
        "kid": "AMP/DEV",
        "alg": "ES256",
        "x5c": [
            "MIIEO...",
            "MIIDK..."
        ]
    }
    

    トランザクションペイロード


    {
      "transactionId": "1000000831360853",
      "originalTransactionId": "1000000806937552",
      "webOrderLineItemId": "1000000063561721",
      "bundleId": "com.adapty.sample_app",
      "productId": "basic_subscription_1_month",
      "subscriptionGroupIdentifier": "27636320",
      "purchaseDate": 1624446341000,
      "originalPurchaseDate": 1619686337000,
      "expiresDate": 1624446641000,
      "quantity": 1,
      "type": "Auto-Renewable Subscription",
      "appAccountToken": "fd12746f-2d3a-46c8-bff8-55b75ed06aca",
      "inAppOwnershipType": "PURCHASED",
      "signedDate": 1624446484882,
      "offerType": 2,
      "offerIdentifier": "basic_subscription_1_month.pay_as_you_go.3_months"
    }
    
    アップルはトランザクション形式を変更し拡張した.私の観点から、今、彼らと働くのはより便利です.あなたの新しいフォーマットについての詳細を学ぶことができますdocumentation . 以下に、最も重要な変更点について説明します.
  • アップル追加appAccountToken このIDはUUIDフォーマットでなければなりません、購入が初期化されているとき、それはモバイルアプリケーションでセットされます.それがセットされるならば、それはこのチェーン(更新、請求問題など)ですべての取引で返されます、そして、あなたはどのユーザーが購入をしたかについて、簡単に理解します.
  • アップルも追加offerType and offerIdentifier 使用されるオファーに関する情報を含むフィールド.以下はoffertypeフィールドの値です.
    1 -イントロ申し込み(アクティブまたは期限切れのサブスクリプションなしで利用可能なユーザーのみ);
    2 -プロモを提供しています.
    3 -コードを提供します.販促申し込みまたは申し込みコードが使われたならば、offerIdentifier keyは使用されるオファーのIDを含んでいます.過去には、サーバー側で提供の使用を追跡することは不可能でした、これは分析を悪化させました.さて、分析のための提供コードを使用することができます.
  • アップル追加inAppOwnershipType フィールドは、ユーザーが製品を購入したかどうか、家族のサブスクリプションのおかげでアクセスを理解するのに役立ちます.使用可能な値:PURCHASED FAMILY_SHARED
  • もう一つの新しいフィールドtype – トランザクションの種類が含まれます.使用可能な値:Auto-Renewable Subscription Non-Consumable Consumable Non-Renewing Subscription
  • Cancellation_date and cancellation_reason フィールドには現在新しい名前があります.revocationDate and revocationReason . リマインダーとして、彼らは払い戻しの結果として予約の取消しの日付と理由を含んでいるので、新しい名前はより論理的に見えます.
  • すべてのキーはcamelcase形式(すべてのApp StoreのサーバーAPIのリクエストのように)で戻ります.
  • すべての日付は、ミリ秒単位でUnixタイムスタンプ形式で表示されます.
  • ユーザの購読状況


    現在のユーザのチェックsubscription status , GETリクエストを送信するhttps://api.storekit.itunes.apple.com/inApps/v1/subscriptions/{originalTransactionId} , どこ{originalTransactionId} はユーザのトランザクションチェーンのIDです.リターンでは、サブスクリプションのすべてのグループの状態でトランザクションを取得します.
    {
      "environment": "Sandbox",
      "bundleId": "com.adapty.sample_app",
      "data": [
        {
          "subscriptionGroupIdentifier": "39636320",
          "lastTransactions": [
            {
              "originalTransactionId": "1000000819078552",
              "status": 2,
              "signedTransactionInfo": "eyJraWQiOi...",
              "signedRenewalInfo": "eyJraWQiOi..."
            }
          ]
        }
      ]
    }
    
    The status キーは、現在のサブスクリプションのステータスは、それに基づいて、あなたは、アプリケーションの有料機能へのアクセスをユーザーに提供する必要があるかどうかを判断することができます.使用可能な値:
    1 -サブスクリプションはアクティブです、ユーザーは有料機能にアクセスできるようにする必要があります.
    2 -サブスクリプションが期限切れになった場合、ユーザーは有料関数にアクセスすることはできません.
    3 -サブスクリプションのステータスは、ユーザーがそれをキャンセルしなかったことを意味する請求リトライですが、支払いに問題が発生します.アップルは60日間カードを請求しようとします.ユーザーは有料関数にアクセスすることはできません.
    4 -サブスクリプションのステータスは猶予期間で、ユーザーがそれをキャンセルしなかったことを意味しますが、支払い問題を経験します.猶予期間はApp Storeに接続されているので、ユーザーは有料機能にアクセスできるようにする必要があります.
    5 -サブスクリプションは払い戻しの結果としてキャンセルされた、ユーザーは有料関数にアクセスすることができない必要があります.
    SignedTransactionInfoキーには、チェーン内の最後のトランザクションに関する情報が含まれます.上の形式についての詳細を見つけることができます.

    サブスクリプション更新情報

    SignedRenewalInfo キーは購読に関する情報を含んでいますrenewal .
    {
      "expirationIntent": 1,
      "originalTransactionId": "1000000819078552",
      "autoRenewProductId": "basic_subscription_1_month",
      "productId": "basic_subscription_1_month",
      "autoRenewStatus": 0,
      "isInBillingRetryPeriod": false,
      "signedDate": 1624520884048
    }
    
    この情報は、次の支払期間中の購読に何が起こるかを理解することができます.たとえば、ユーザーが自動更新をキャンセルした場合は、別のサブスクリプションプランに切り替えるには、それらを提供したり、プロモ提供を提供することができます.これは、私はすぐについて説明しますサーバーの通知の助けを借りて、この種のイベントを追跡するのは便利です.

    ユーザーの履歴


    ユーザーの取得transaction history , GETリクエストを送信するhttps://api.storekit.itunes.apple.com/inApps/v1/history/{originalTransactionId} , どこ{originalTransactionId} はユーザのトランザクションのチェーンのIDです.返されるトランザクションの配列を取得します.
    {
      "revision": "1625872984000_1000000212854038",
      "bundleId": "com.adapty.sample_app",
      "environment": "Sandbox",
      "hasMore": true,
      "signedTransactions": [
      "eyJraWQiOiJ...",
          "joiRVMyNeyX...",
          "5MnkvOTlOZl...",
          ...
          ]
    }
    
    要求は、20以上のトランザクションを含むことができます.ユーザーがもっとhasMore フラグの値はtrue . あなたが次の取引ページを必要とするならばrevision パラメータを取得するそれは同じキーから値を含んでいます.

    サーバトランザクション通知


    サーバーの通知は、新しい購入、更新、請求の問題などについての情報を得るために役立ちます.これは、より正確な分析を構築するのに役立ちますだけでなく、加入者のステータスを管理簡素化します.
    既存のサーバー通知(V 1)は、ほとんどの問題を解決することができますが、時々不便です.ほとんどの場合、ユーザのたった1つのアクションに対していくつかの通知を受け取るときの状況についてです.例えば、ユーザーがサブスクリプションをアップグレードすると、Appleは2つの通知を送信します.DID_CHANGE_RENEWAL_STATUS and INTERACTIVE_RENEWAL . 現在このケースを処理するために、あなたはどうにかステータスを保存して、2番目の通知が送られたかどうかチェックする必要があります.サーバー通知(V 2)の新しいバージョンでは、ユーザーの1つの行動のための1つの通知だけがあります.これはずっと便利です.
    サーバー通知の第2のバージョンは、新しいイベントを特徴としますOFFER_REDEEMED , EXPIRED , and GRACE_PERIOD_EXPIRED . 彼らは管理者のステータスをはるかに簡単になります.SUBSCRIBED and PRICE_INCREASE イベントは、最初のバージョンからのイベントを改善されます.

    通知タイプ


    通知は現在、このように、ユーザーの任意のアクションの1つの通知は、何が起こったの理解に十分です.

    通知タイプ
    {
      "notificationType": "SUBSCRIBED",
      "subtype": "INITIAL_BUY",
      "version": 2,
      "data": {
        "environment": "Sandbox",
        "bundleId": "com.adapty.sample_app",
        "appAppleId": 739104078,
        "bundleVersion": 1,
        "signedTransactionInfo": "eyJraWQiOi...",
        "signedRenewalInfo": "eyJraWQiOi..."
      }
    }
    
    サーバー通知は、私が以前に述べたJWS形式でトランザクションと更新に関する情報を含みます.

    サンドボックス環境の操作


    購入をテストするには、サンドボックス環境のURLを使用する必要があります.https://api.storekit-sandbox.itunes.apple.com.サーバー通知の新しいバージョンはまだテストのために利用できません.それが利用可能であれば、生産とサンドボックスの通知のためのさまざまなURLを指定することが可能になります.テスト用のV 1をサンドボックス、V 1を選択できます.
    また、App Storeに接続することができます:
    *サンドボックスユーザーのためのクリア購入履歴は、あなたがもうそれを行うには、新しいアカウントを作成する必要がないことを意味します.
  • サンドボックスユーザーのストア国を変更します.
  • 変更サンドボックスサブスクリプションの更新期間は、例えば、5分の代わりに1時間続く毎月の購入を行うことができます.
  • 結論


    アップルは、サーバー側でのアプリ内購入とサブスクリプションとの作業を大幅に改善しました.私の観点から、ここで最も有用な新機能があります
  • フル本格的な販促提供と提供コードのサポート;
  • シンプルでより有益なサーバーの通知;
  • 機会は、単純なAPIの呼び出しでは、現在のサブスクリプションのステータスについて学ぶ
  • ユーザーのサンドボックスの購入履歴をクリアします.
  • 新しいAPIへの切り替えは難しくないでしょうoriginalTransactionId すべての領収書.それはすでにあなたのベースに含まれている可能性が高いです.