{"id":137909,"date":"2021-07-08T00:00:00","date_gmt":"2021-07-08T00:00:00","guid":{"rendered":"https:\/\/adapty.io\/pl-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\/pl\/blog\/storekit-2\/","title":{"rendered":"Co nowego w StoreKit 2 API i jak Apple upro\u015bci\u0142o integracj\u0119 zakup\u00f3w w aplikacji"},"content":{"rendered":"\n

Apple wprowadzi\u0142o now\u0105 wersj\u0119 StoreKit 2 podczas wydarzenia WWDC 2021, kt\u00f3re odby\u0142o si\u0119 stosunkowo niedawno. Jest to framework odpowiedzialny za dokonywanie zakup\u00f3w w systemie iOS. Udzia\u0142 aplikacji z funkcjami zakupu w aplikacji (in-app purchase) i subskrypcji stale ro\u015bnie, a Apple znacznie upro\u015bci\u0142o integracj\u0119 zakup\u00f3w w aplikacji, wydaj\u0105c StoreKit 2. Dzisiaj rozwa\u017cymy wsp\u00f3\u0142prac\u0119 ze StoreKit 2 ze strony serwera, innymi s\u0142owy, za pomoc\u0105 API serwera App Store.<\/p>\n\n\n\n

\u017b\u0105danie uwierzytelnienia<\/h2>\n\n\n\n

W bie\u017c\u0105cej wersji interfejsu API, aby wys\u0142a\u0107 \u017c\u0105danie, potrzebujesz Shared Secret. Jest to tajny, sta\u0142y ci\u0105g, kt\u00f3ry mo\u017cna uzyska\u0107 w App Store Connect. Nowa wersja API u\u017cywa standardu JSON Web Token (JWT) do uwierzytelniania \u017c\u0105da\u0144.   <\/p>\n\n\n\n

Generowanie kluczy <\/h3>\n\n\n\n

Przede wszystkim, utw\u00f3rz klucz prywatny<\/a> kt\u00f3ry zostanie wykorzystany do autoryzacji \u017c\u0105da\u0144. Otw\u00f3rz App Store Connect i przejd\u017a do sekcji u\u017cytkownicy i dost\u0119p (Users and Access), a nast\u0119pnie do zak\u0142adki klucze (Keys). Wybierz typ klucza „In-App Purchase”. Pobierz nowy klucz. Potrzebny b\u0119dzie r\u00f3wnie\u017c jego identyfikator-mo\u017cesz go skopiowa\u0107 na tej samej stronie, co Issue ID, kt\u00f3ry mo\u017cna znale\u017a\u0107 w zak\u0142adce API w App Store Connect.<\/p>\n\n\n\n

\"Creating
Tworzenie klucza prywatnego do pracy z API serwera App Store<\/em><\/figcaption><\/figure>\n\n\n\n

Tworzenie tokena<\/h3>\n\n\n\n

Nast\u0119pnym krokiem jest utworzenie tokena, kt\u00f3ry b\u0119dzie u\u017cywany do autoryzacji \u017c\u0105da\u0144. Proces ten jest szczeg\u00f3\u0142owo opisany w dokumentacji<\/a>, nie ma wi\u0119c powodu, by po\u015bwi\u0119ca\u0107 temu zbyt wiele uwagi. Oto przyk\u0142ad gotowej implementacji dla Pythona. Warto zauwa\u017cy\u0107, \u017ce nie ma sensu generowa\u0107 nowego tokena dla ka\u017cdego nowego \u017c\u0105dania. Podczas tworzenia tokena ustawiasz jego \u017cywotno\u015b\u0107 na maksymalnie 60 minut i u\u017cywasz tego samego tokena przez ten czas.<\/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

Podpisane transakcje<\/h2>\n\n\n\n

W nowej wersji API wszystkie transakcje zwracane s\u0105 w standardzie JSON Web Signature (JWS). Jest to ci\u0105g sk\u0142adaj\u0105cy si\u0119 z trzech cz\u0119\u015bci podzielonych kropkami.  <\/p>\n\n\n\n

    \n
  1. Nag\u0142\u00f3wek Base64.<\/li>\n\n\n\n
  2. Zawarto\u015b\u0107 transakcji Base64.<\/li>\n\n\n\n
  3. Podpis transakcji.<\/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

    Nag\u0142\u00f3wek transakcji<\/h3>\n\n\n\n

    Nag\u0142\u00f3wek jest potrzebny, aby upewni\u0107 si\u0119, \u017ce transakcja jest autentyczna. Klucz Alg zawiera algorytm szyfrowania, klucz x5c zawiera \u0142a\u0144cuch certyfikat\u00f3w.<\/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

    Zawarto\u015b\u0107 transakcji<\/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 zmieni\u0142o i rozszerzy\u0142o format transakcji. Z mojego punktu widzenia praca z nimi jest teraz wygodniejsza. Szczeg\u00f3\u0142y dotycz\u0105ce nowego formatu mo\u017cna znale\u017a\u0107 w dokumentacji<\/a>. Poni\u017cej opisz\u0119 najwa\u017cniejsze zmiany.    <\/p>\n\n\n\n