{"id":137886,"date":"2021-07-08T00:00:00","date_gmt":"2021-07-08T00:00:00","guid":{"rendered":"https:\/\/adapty.io\/de-storekit-2\/"},"modified":"2021-07-08T00:00:00","modified_gmt":"2021-07-08T00:00:00","slug":"storekit-2","status":"publish","type":"post","link":"https:\/\/adapty.io\/de\/blog\/storekit-2\/","title":{"rendered":"Was ist neu an der StoreKit 2 API und wie Apple die Integration von In-App-K\u00e4ufen vereinfacht hat"},"content":{"rendered":"\n

Apple hat letztens w\u00e4hrend der WWDC 2021 eine neue Version von StoreKit 2 pr\u00e4sentiert. Dabei handelt es sich um ein Framework, das f\u00fcr K\u00e4ufe in iOS verantwortlich ist. Der Anteil an Apps mit In-App-K\u00e4ufen und Abonnements w\u00e4chst stetig und Apple hat mit der Ver\u00f6ffentlichung von StoreKit 2 die Integration von In-App-K\u00e4ufen in die App deutlich vereinfacht. In dem heutigen Artikel beleuchten wir die Arbeit mit StoreKit 2 auf der Serverseite (sprich mit Hilfe der App Store Server API).<\/p>\n\n\n\n

Anforderung der Authentifizierung<\/h2>\n\n\n\n

In der aktuellen API-Version ben\u00f6tigen Sie das gemeinsame Geheimnis (shared secret), um eine Anfrage zu senden. Dies ist eine geheime feste Zeichenfolge, die Sie in App Store Connect erhalten. Die neue Version der API verwendet den JSON Web Token (JWT)-Standard f\u00fcr die Anforderung der Authentifizierung.  <\/p>\n\n\n\n

Generierung des Keys<\/h3>\n\n\n\n

Zun\u00e4chst m\u00fcssen Sie einen privaten Key<\/a> erstellen, der zur Autorisierung der Anfragen verwendet wird. \u00d6ffnen Sie App Store Connect und gehen Sie zum Abschnitt Nnutzer und Zugriff und anschlie\u00dfend zur Registerkarte Key. W\u00e4hlen Sie den Key-Typ f\u00fcr den In-App-Kauf aus und laden Sie einen neuen Key herunter. Sie ben\u00f6tigen auch seine ID. Diese k\u00f6nnen Sie auf derselben Seite wie die Problem-ID kopieren, die auf der Registerkarte App Store Connect API zu finden ist.<\/p>\n\n\n\n

\"Creating
Erstellung eines privaten Keys f\u00fcr die Arbeit mit der App Store Server API<\/em><\/figcaption><\/figure>\n\n\n\n

Erstellung eines Tokens<\/h3>\n\n\n\n

Als n\u00e4chstes erstellen Sie einen Token, der zum Autorisieren der Anforderungen verwendet wird. Dieser Vorgang wird in der Dokumentation <\/a>ausf\u00fchrlich beschrieben, weswegen wir an dieser Stelle nicht weiter darauf eingehen. Stattdessen zeigen wir Ihnen ein Beispiel f\u00fcr eine fertige Implementierung f\u00fcr Python. Es ergibt keinen Sinn, f\u00fcr jede neue Anfrage einen neuen Token zu generieren. Beim Erstellen eines Tokens legen Sie dessen Lebensdauer auf bis zu 60 Minuten fest und verwenden in dieser Zeit denselben Token. <\/p>\n\n\n\n

<\/path><\/path><\/svg><\/span>
import<\/span> time<\/span>,<\/span> uuid<\/span><\/span>\nfrom<\/span> authlib<\/span>.<\/span>jose <\/span>import<\/span> jwt<\/span><\/span>\n<\/span>\nBUNDLE_ID <\/span>=<\/span> <\/span>'<\/span>com.adapty.sample_app<\/span>'<\/span><\/span>\nISSUER_ID <\/span>=<\/span> <\/span>'<\/span>4336a124-f214-4d40-883b-6db275b5e4aa<\/span>'<\/span><\/span>\nKEY_ID <\/span>=<\/span> <\/span>'<\/span>J65UYBDA74<\/span>'<\/span><\/span>\nPRIVATE_KEY <\/span>=<\/span> <\/span>'''<\/span><\/span>\n-----BEGIN PRIVATE KEY-----<\/span><\/span>\nMIGTAgMGByqGSMBHkAQQgR\/fR+3Lkg4...<\/span><\/span>\n-----END PRIVATE KEY-----<\/span><\/span>\n'''<\/span><\/span>\n<\/span>\nissue_time <\/span>=<\/span> <\/span>round<\/span>(<\/span>time<\/span>.<\/span>time<\/span>())<\/span><\/span>\nexpiration_time <\/span>=<\/span> issue_time <\/span>+<\/span> <\/span>60<\/span> <\/span>*<\/span> <\/span>60<\/span> <\/span># 1 hour expiration<\/span><\/span>\n<\/span>\n<\/span>\nheader <\/span>=<\/span> <\/span>{<\/span><\/span>\n <\/span>'<\/span>alg<\/span>'<\/span>:<\/span> <\/span>'<\/span>ES256<\/span>'<\/span>,<\/span><\/span>\n <\/span>'<\/span>kid<\/span>'<\/span>:<\/span> KEY_ID<\/span>,<\/span><\/span>\n <\/span>'<\/span>typ<\/span>'<\/span>:<\/span> <\/span>'<\/span>JWT<\/span>'<\/span><\/span>\n}<\/span><\/span>\n<\/span>\npayload <\/span>=<\/span> <\/span>{<\/span><\/span>\n <\/span>'<\/span>iss<\/span>'<\/span>:<\/span> ISSUER_ID<\/span>,<\/span><\/span>\n <\/span>'<\/span>iat<\/span>'<\/span>:<\/span> issue_time<\/span>,<\/span><\/span>\n <\/span>'<\/span>exp<\/span>'<\/span>:<\/span> expiration_time<\/span>,<\/span><\/span>\n <\/span>'<\/span>aud<\/span>'<\/span>:<\/span> <\/span>'<\/span>appstoreconnect-v1<\/span>'<\/span>,<\/span><\/span>\n <\/span>'<\/span>nonce<\/span>'<\/span>:<\/span> <\/span>str<\/span>(<\/span>uuid<\/span>.<\/span>uuid4<\/span>()),<\/span><\/span>\n <\/span>'<\/span>bid<\/span>'<\/span>:<\/span> BUNDLE_ID<\/span><\/span>\n}<\/span><\/span>\n<\/span>\ntoken_encoded <\/span>=<\/span> jwt<\/span>.<\/span>encode<\/span>(<\/span>header<\/span>,<\/span> payload<\/span>,<\/span> PRIVATE_KEY<\/span>)<\/span><\/span>\ntoken_decoded <\/span>=<\/span> token_encoded<\/span>.<\/span>decode<\/span>()<\/span><\/span>\n<\/span>\nauthorization_header <\/span>=<\/span> <\/span>{<\/span><\/span>\n <\/span>'<\/span>Authorization<\/span>'<\/span>:<\/span> <\/span>f<\/span>'Bearer <\/span>{<\/span>token_decoded<\/span>}<\/span>'<\/span><\/span>\n}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n

Unterzeichnete Transaktionen<\/h2>\n\n\n\n

In der neuen API-Version werden alle Transaktionen im JSON Web Signature (JWS)-Standard zur\u00fcckgegeben. Dies ist eine Zeichenfolge, die aus drei Teilen besteht, die durch Punkte getrennt sind.  <\/p>\n\n\n\n

    \n
  1. Base64 Header.<\/li>\n\n\n\n
  2. Base64 Transaction Payload.<\/li>\n\n\n\n
  3. Transaction Signature.<\/li>\n<\/ol>\n\n\n\n
    <\/path><\/path><\/svg><\/span>
    Base<\/span>64<\/span>(header) + <\/span>"<\/span>.<\/span>"<\/span> + Base<\/span>64<\/span>(payload) + <\/span>"<\/span>.<\/span>"<\/span> + sign(Base<\/span>64<\/span>(header) + <\/span>"<\/span>.<\/span>"<\/span> + Base<\/span>64<\/span>(payload))<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n

    Transaction Header<\/h3>\n\n\n\n

    Der Header ist wichtig, damit Sie sicher sein k\u00f6nnen, dass die Transaktion echt ist. Der Alg-Key enth\u00e4lt einen Verschl\u00fcsselungsalgorithmus, der x5c-Key enth\u00e4lt eine Zertifikatskette.<\/p>\n\n\n\n

    <\/path><\/path><\/svg><\/span>
    {<\/span><\/span>\n  <\/span>"<\/span>kid<\/span>"<\/span>:<\/span> <\/span>"<\/span>AMP\/DEV<\/span>"<\/span>,<\/span><\/span>\n  <\/span>"<\/span>alg<\/span>"<\/span>:<\/span> <\/span>"<\/span>ES256<\/span>"<\/span>,<\/span><\/span>\n  <\/span>"<\/span>x5c<\/span>"<\/span>:<\/span> <\/span>[<\/span><\/span>\n    <\/span>"<\/span>MIIEO...<\/span>"<\/span>,<\/span><\/span>\n    <\/span>"<\/span>MIIDK...<\/span>"<\/span><\/span>\n  <\/span>]<\/span><\/span>\n}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n

    Transaction Payload<\/h3>\n\n\n\n
    <\/path><\/path><\/svg><\/span>
    {<\/span><\/span>\n  <\/span>"<\/span>transactionId<\/span>"<\/span>:<\/span> <\/span>"<\/span>1000000831360853<\/span>"<\/span>,<\/span><\/span>\n  <\/span>"<\/span>originalTransactionId<\/span>"<\/span>:<\/span> <\/span>"<\/span>1000000806937552<\/span>"<\/span>,<\/span><\/span>\n  <\/span>"<\/span>webOrderLineItemId<\/span>"<\/span>:<\/span> <\/span>"<\/span>1000000063561721<\/span>"<\/span>,<\/span><\/span>\n  <\/span>"<\/span>bundleId<\/span>"<\/span>:<\/span> <\/span>"<\/span>com.adapty.sample_app<\/span>"<\/span>,<\/span><\/span>\n  <\/span>"<\/span>productId<\/span>"<\/span>:<\/span> <\/span>"<\/span>basic_subscription_1_month<\/span>"<\/span>,<\/span><\/span>\n  <\/span>"<\/span>subscriptionGroupIdentifier<\/span>"<\/span>:<\/span> <\/span>"<\/span>27636320<\/span>"<\/span>,<\/span><\/span>\n  <\/span>"<\/span>purchaseDate<\/span>"<\/span>:<\/span> <\/span>1624446341000<\/span>,<\/span><\/span>\n  <\/span>"<\/span>originalPurchaseDate<\/span>"<\/span>:<\/span> <\/span>1619686337000<\/span>,<\/span><\/span>\n  <\/span>"<\/span>expiresDate<\/span>"<\/span>:<\/span> <\/span>1624446641000<\/span>,<\/span><\/span>\n  <\/span>"<\/span>quantity<\/span>"<\/span>:<\/span> <\/span>1<\/span>,<\/span><\/span>\n  <\/span>"<\/span>type<\/span>"<\/span>:<\/span> <\/span>"<\/span>Auto-Renewable Subscription<\/span>"<\/span>,<\/span><\/span>\n  <\/span>"<\/span>appAccountToken<\/span>"<\/span>:<\/span> <\/span>"<\/span>fd12746f-2d3a-46c8-bff8-55b75ed06aca<\/span>"<\/span>,<\/span><\/span>\n  <\/span>"<\/span>inAppOwnershipType<\/span>"<\/span>:<\/span> <\/span>"<\/span>PURCHASED<\/span>"<\/span>,<\/span><\/span>\n  <\/span>"<\/span>signedDate<\/span>"<\/span>:<\/span> <\/span>1624446484882<\/span>,<\/span><\/span>\n  <\/span>"<\/span>offerType<\/span>"<\/span>:<\/span> <\/span>2<\/span>,<\/span><\/span>\n  <\/span>"<\/span>offerIdentifier<\/span>"<\/span>:<\/span> <\/span>"<\/span>basic_subscription_1_month.pay_as_you_go.3_months<\/span>"<\/span><\/span>\n}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n

    Apple hat das Transaktionsformat sowohl ge\u00e4ndert als auch erweitert. F\u00fcr mich ist es jetzt einfacher zu verwenden. Einzelheiten zum neuen Format finden Sie in der Dokumentation<\/a>. Im Folgenden beschreibe ich die wichtigsten \u00c4nderungen.<\/p>\n\n\n\n