Novedades de la API de StoreKit 2 y cómo facilitó la integración de compras en la aplicación

En la reciente WWDC 2021 se presentó una nueva versión de StoreKit 2. Es un framework que se encarga de realizar compras en iOS. La proporción de aplicaciones con suscripciones y compras dentro de la aplicación está creciendo de manera constante, y con el lanzamiento de StoreKit 2, Apple ha facilitado mucho la integración de compras en la aplicación. Hoy veremos cómo trabajar con StoreKit 2 desde el lado del servidor, es decir, usando la API de App Store Server.





Autenticar solicitudes

En la versión actual de la API, se requiere un secreto compartido para enviar una solicitud. Esta es una cadena fija secreta que se puede obtener en App Store Connect. La nueva versión de la API utiliza el estándar JSON Web Token (JWT) para autenticar solicitudes.





Generación de claves

En primer lugar, debe crear una clave privada con la que se firmarán las solicitudes. Esto se hace en App Store Connect en Users and Access. Allí debe ir a la pestaña Claves y seleccionar el tipo de clave Compra en la aplicación. Después de la creación, la clave debe descargarse. También necesitará su ID, que se puede copiar en la misma página, y el ID del emisor, que se encuentra en la pestaña App Store Connect API.





Creación de una clave privada para trabajar con la API del servidor de la App Store
Creación de una clave privada para trabajar con la API del servidor de la App Store

Creación de tokens

, . , , Python. , . 60 .





JWT- App Store Server API
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}'
}
      
      



(signed transactions)

API JSON Web Signature (JWS). , .





  1. Base64 .





  2. Base64 .





  3. .





Base64(header) + "." + Base64(payload) + "." + sign(Base64(header) + "." + Base64(payload))
      
      



, . alg , x5c — .





{
	"kid": "AMP/DEV",
	"alg": "ES256",
	"x5c": [
		"MIIEO...",
		"MIIDK..."
	]
}
      
      



Apple , , . , .





  • appAccountToken



    , . UUID . , (, .), , .





  • offerType



    offerIdentifier



    , , . offerType



    :





    • 1



      — ( )





    • 2



      — ( )





    • 3







  • ( 2



    3



    ), offerIdentifier



    . , . .





  • inAppOwnershipType



    , , . :





    • PURCHASED







    • FAMILY_SHARED







  • type



    , . :





    • Auto-Renewable Subscription







    • Non-Consumable







    • Consumable







    • Non-Renewing Subscription







  • cancellation_date



    cancellation_reason



    revocationDate



    revocationReason



    . , , .





  • camelCase ( App Store Server API).





  • Unix timestamp .





{
	"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"
}
      
      



GET https://api.storekit.itunes.apple.com/inApps/v1/subscriptions/{originalTransactionId}



, {originalTransactionId}



— . .





{
	"environment": "Sandbox",
	"bundleId": "com.adapty.sample_app",
	"data": [
		{
			"subscriptionGroupIdentifier": "39636320",
			"lastTransactions": [
				{
					"originalTransactionId": "1000000819078552",
					"status": 2,
					"signedTransactionInfo": "eyJraWQiOi...",
					"signedRenewalInfo": "eyJraWQiOi..."
				}
			]
		}
	]
}
      
      



status



, , , . :





  • 1



    — , .





  • 2



    — , .





  • 3



    — Billing Retry, , . Apple 60 . .





  • 4



    — Grace Period, , . App Store Connect Grace Period, .





  • 5



    — , .





signedTransactionInfo



, .





signedRenewalInfo



.





, . , , , . , .





{
	"expirationIntent": 1,
	"originalTransactionId": "1000000819078552",
	"autoRenewProductId": "basic_subscription_1_month",
	"productId": "basic_subscription_1_month",
	"autoRenewStatus": 0,
	"isInBillingRetryPeriod": false,
	"signedDate": 1624520884048
}
      
      



, GET https://api.storekit.itunes.apple.com/inApps/v1/history/{originalTransactionId}



, {originalTransactionId}



— . , .





20 , , hasMore



true



. , GET- revision



, .





{
	"revision": "1625872984000_1000000212854038",
	"bundleId": "com.adapty.sample_app",
	"environment": "Sandbox",
	"hasMore": true,
	"signedTransactions": [
		"eyJraWQiOiJ...",
		"joiRVMyNeyX...",
		"5MnkvOTlOZl...",
		...
	]
}
      
      



, , . , .





(V1) , . , . , Apple : DID_CHANGE_RENEWAL_STATUS



INTERACTIVE_RENEWAL



, , - , , . (V2), , .





OFFER_REDEEMED



, EXPIRED



GRACE_PERIOD_EXPIRED



, . SUBSCRIBED



PRICE_INCREASE



— .





JWS.





Tipos de notificaciones

, , , .





Subtipos de notificación
{
	"notificationType": "SUBSCRIBED",
	"subtype": "INITIAL_BUY",
	"version": 2,
	"data": {
		"environment": "Sandbox",
		"bundleId": "com.adapty.sample_app",
		"appAppleId": 739104078,
		"bundleVersion": 1,
		"signedTransactionInfo": "eyJraWQiOi...",
		"signedRenewalInfo": "eyJraWQiOi..."
	}
}
      
      



Sandbox

, , URL Sandbox : https://api.storekit-sandbox.itunes.apple.com



.





, , URL Production Sandbox . Sandbox V2, Production V1.





App Store Connect :





  • Sandbox , .





  • Sandbox .





  • Sandbox . , , 1 , 5 , .





Apple . , :





  • ;





  • ;





  • ;





  • Sandbox .





API , receipt originalTransactionId. , .





, — . Adapty :





  • .





  • , .





  • / .





  • .





  • .





  • Open source SDK .





, .








All Articles