{"id":137864,"date":"2021-07-08T00:00:00","date_gmt":"2021-07-08T00:00:00","guid":{"rendered":"https:\/\/adapty.io\/fr-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\/fr\/blog\/storekit-2\/","title":{"rendered":"Quelles sont les nouveaut\u00e9s de l’API StoreKit 2 et comment Apple a simplifi\u00e9 l’int\u00e9gration des achats int\u00e9gr\u00e9s aux applications."},"content":{"rendered":"\n

Apple a pr\u00e9sent\u00e9 une nouvelle version de StoreKit 2 lors de la WWDC 2021 qui s’est d\u00e9roul\u00e9e r\u00e9cemment. Il s’agit d’un cadre responsable de la r\u00e9alisation des achats dans iOS. Une part des applications (app) avec des fonctions d’achat int\u00e9gr\u00e9 (in-app purchase) et d’abonnement (subscription)  ne cesse de cro\u00eetre, et Apple a consid\u00e9rablement simplifi\u00e9 l’int\u00e9gration des achats int\u00e9gr\u00e9s \u00e0 l’application en publiant StoreKit 2. Aujourd’hui, nous allons envisager de travailler avec StoreKit 2 sur la partie du serveur, autrement dit, \u00e0 l’aide de App Store Server API.<\/p>\n\n\n\n

Requ\u00eate d’authentification<\/h2>\n\n\n\n

Dans la version actuelle de l’API, vous avez besoin du Secret Partag\u00e9 (shared secret) pour envoyer une requ\u00eate. Il s’agit d’une cha\u00eene secr\u00e8te fixe que vous pouvez obtenir dans App Store Connect. Une nouvelle version de l’API utilise la norme JSON Web Token (JWT) pour l’authentification des requ\u00eates.   <\/p>\n\n\n\n

G\u00e9n\u00e9ration de cl\u00e9s <\/h3>\n\n\n\n

Tout d’abord, cr\u00e9ez une cl\u00e9 priv\u00e9e<\/a> qui sera utilis\u00e9e pour autoriser les demandes. Ouvrez App Store Connect et allez dans la section Users and Access, puis dans l’onglet Keys. S\u00e9lectionnez le type de cl\u00e9 pour les achats int\u00e9gr\u00e9s \u00e0 l’application. T\u00e9l\u00e9chargez une nouvelle cl\u00e9. Vous aurez \u00e9galement besoin de son ID – vous pouvez le copier sur la m\u00eame page que l’Issue ID qui se trouve dans l’onglet App Store Connect API.<\/p>\n\n\n\n

\"Creating
Cr\u00e9ation d’une cl\u00e9 priv\u00e9e pour travailler avec App Store Server API<\/em><\/figcaption><\/figure>\n\n\n\n

Cr\u00e9ation d’un jeton<\/h3>\n\n\n\n

L’\u00e9tape suivante consiste \u00e0 cr\u00e9er un jeton qui sera utilis\u00e9 pour autoriser les requ\u00eates. Ce processus est d\u00e9crit en d\u00e9tail dans documentation<\/a>, il n’y a donc aucune raison d’y pr\u00eater trop d’attention. Voici un exemple d’une impl\u00e9mentation pr\u00eate \u00e0 l’emploi pour Python. Il convient de noter qu’il est inutile de g\u00e9n\u00e9rer un nouveau jeton pour chaque nouvelle requ\u00eate. Lorsque vous cr\u00e9ez un jeton, vous fixez sa dur\u00e9e de vie \u00e0 60 minutes maximum et vous utilisez le m\u00eame jeton pendant cette p\u00e9riode. <\/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

Transactions sign\u00e9es<\/h2>\n\n\n\n

Dans une nouvelle version de l’API, toutes les transactions sont renvoy\u00e9es dans la norme JSON Web Signature (JWS). Il s’agit d’une cha\u00eene compos\u00e9e de trois parties divis\u00e9es par des points.  <\/p>\n\n\n\n

    \n
  1. En-t\u00eate en base64.<\/li>\n\n\n\n
  2. Donn\u00e9es utiles de la transaction en base64.<\/li>\n\n\n\n
  3. Signature de la transaction.<\/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

    En-t\u00eate de la transaction<\/h3>\n\n\n\n

    Un en-t\u00eate est n\u00e9cessaire pour s’assurer que la transaction est authentique. La cl\u00e9 Alg contient un algorithme de cryptage, la cl\u00e9 x5c contient une cha\u00eene de certificats.<\/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

    Donn\u00e9es utiles de la transaction<\/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 a modifi\u00e9 et \u00e9tendu le format de la transaction. De mon point de vue, maintenant, c’est plus pratique de travailler avec eux. Vous pouvez obtenir des d\u00e9tails sur un nouveau format dans documentation<\/a>. Je vais d\u00e9crire ci-dessous les changements les plus importants.    <\/p>\n\n\n\n