![Las compras dentro de la aplicación de iOS, parte 5: lista de códigos SKError y cómo manejarlos 5 62fdf1ee3ac056e02f757705 jp android tutorial 1 configuration 9](https://adapty.io/wp-content/uploads/2023/01/62fdf1ee3ac056e02f757705_jp-android-tutorial-1-configuration-9.png)
Tutorial
septiembre 6, 2022
Updated: marzo 20, 2023
Durante la Conferencia Mundial de Desarrolladores de Apple (WWDC) 2021 que tuvo lugar recientemente, Apple presentó una nueva versión de StoreKit 2. Se trata de un framework responsable de las compras en iOS. La proporción de aplicaciones (app) con funciones de compra y suscripción (subscription) dentro de la aplicación crece constantemente, y Apple ha simplificado significativamente la integración de las compras dentro de la aplicación con el lanzamiento de StoreKit 2. Hoy analizaremos el trabajo con StoreKit 2 en la parte del servidor, es decir, con la ayuda de App Store Server API.
En la versión actual de la API, necesitas el secreto compartido (shared secret) para enviar una solicitud. Se trata de una cadena secreta fija que puedes obtener en App Store Connect. La nueva versión de la API utiliza el estándar JSON Web Token (JWT) para la autenticación de las solicitudes.
En primer lugar, crea una clave privada que se utilizará para autorizar las solicitudes. Abre App Store Connect y ve a la sección Users y Access, y a continuación a la pestaña Keys. Selecciona el tipo de clave de compras dentro de la aplicación. Descarga una nueva clave. También necesitarás su ID: puedes copiarlo en la misma página que el ID de la compra dentro de la aplicación, que se encuentra en la pestaña de la API de App Store Connect.
El siguiente paso es crear un token que se utilizará para autorizar las solicitudes. Este proceso se describe detalladamente en la documentación, así que no hay razón para prestarle demasiada atención. Aquí tienes un ejemplo de una implementación ya hecha para Python. Cabe destacar que no tiene sentido generar un nuevo token para cada nueva solicitud. Al crear un token, establece su vida útil en un máximo de 60 minutos y utiliza el mismo token durante este periodo.
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}'
}
En una nueva versión de la API, todas las transacciones se devuelven en el estándar JSON Web Signature (JWS). Se trata de una cadena formada por tres partes divididas por puntos.
Base64(header) + "." + Base64(payload) + "." + sign(Base64(header) + "." + Base64(payload))
Se necesita un encabezado para asegurarse de que la transacción es auténtica. La clave Alg contiene un algoritmo de encriptación, la clave x5c contiene una cadena de certificados.
{
"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"
}
Apple ha cambiado y ampliado el formato de las transacciones. Desde mi punto de vista, ahora es más cómodo trabajar con ellos. Puedes conocer los detalles del nuevo formato en la documentación. A continuación, describiré los cambios más importantes.
Si se ha utilizado una oferta promocional o un código de oferta, la clave offerIdentifier contendrá el ID de la oferta utilizada. Antes, era imposible hacer un seguimiento del uso de la oferta en el lado del servidor (server side), lo que empeoraba los análisis. Ahora, puedes utilizar los códigos de oferta para los análisis.
2024 subscription benchmarks and insights
Get your free copy of our latest subscription report to stay ahead in 2024.
Para comprobar el estado de la suscripción del usuario actual, envía una solicitud GET a https://api.storekit.itunes.apple.com/inApps/v1/subscriptions/{originalTransactionId}, donde {originalTransactionId} es el ID de cualquier cadena de transacciones del usuario. A cambio, obtendrás las transacciones con los estados de cada grupo de suscripciones.
{
"environment": "Sandbox",
"bundleId": "com.adapty.sample_app",
"data": [
{
"subscriptionGroupIdentifier": "39636320",
"lastTransactions": [
{
"originalTransactionId": "1000000819078552",
"status": 2,
"signedTransactionInfo": "eyJraWQiOi...",
"signedRenewalInfo": "eyJraWQiOi..."
}
]
}
]
}
La clave de estado muestra el estado actual de la suscripción, en base a ella, puedes decidir si debes proporcionar a un usuario acceso a las funciones de pago de la aplicación. Valores posibles:
La clave SignedTransactionInfo contiene la información sobre la última transacción de la cadena. Más arriba encontrarás los detalles sobre su formato.
La clave SignedRenewalInfo contiene la información sobre la renovación de la suscripción.
{
"expirationIntent": 1,
"originalTransactionId": "1000000819078552",
"autoRenewProductId": "basic_subscription_1_month",
"productId": "basic_subscription_1_month",
"autoRenewStatus": 0,
"isInBillingRetryPeriod": false,
"signedDate": 1624520884048
}
Esta información nos permite saber qué ocurrirá con la suscripción durante el siguiente periodo de pago. Por ejemplo, si ves que un usuario ha cancelado la renovación automática, puedes ofrecerle cambiar a otro plan de suscripción o proporcionarle una oferta promocional. Es conveniente hacer un seguimiento de este tipo de eventos (events) con la ayuda de las notificaciones del servidor (server notifications), de las que te hablaré pronto.
Para obtener el historial de transacciones del usuario, envía una solicitud GET a https://api.storekit.itunes.apple.com/inApps/v1/history/{originalTransactionId}, donde {originalTransactionId} es el ID de cualquier cadena de transacciones del usuario. A cambio, obtendrás una matriz de transacciones ordenadas por tiempo.
{
"revision": "1625872984000_1000000212854038",
"bundleId": "com.adapty.sample_app",
"environment": "Sandbox",
"hasMore": true,
"signedTransactions": [
"eyJraWQiOiJ...",
"joiRVMyNeyX...",
"5MnkvOTlOZl...",
...
]
}
Una solicitud no puede contener más de 20 transacciones. Si un usuario tiene más, el valor de la marca hasMore será verdadero. Si necesitas la siguiente página de transacciones, envía de nuevo la solicitud con el parámetro GET de revisión conteniendo. Este contendrá el valor de la misma clave.
Las notificaciones del servidor ayudan a obtener información sobre nuevas compras, renovaciones, problemas de facturación, etc. Esto ayuda a crear un análisis más preciso, así como a simplificar la gestión del estado del suscriptor.
Las notificaciones del servidor existentes (V1) pueden resolver la mayoría de los problemas, pero a veces son inconvenientes. Principalmente, se trata de la situación en la que se reciben varias notificaciones por una sola acción de un usuario. Por ejemplo, ahora, al actualizar un usuario una suscripción, Apple envía dos notificaciones DID_CHANGE_RENEWAL_STATUS y INTERACTIVE_RENEWAL. Para procesar este caso actualmente, tienes que guardar el estado de alguna manera y comprobar si se ha enviado la segunda notificación. En la nueva versión de las notificaciones del servidor (V2), sólo hay una notificación para una acción de un usuario. Esto es mucho más conveniente.
La segunda versión de las notificaciones al servidor presenta nuevos eventos: OFFER_REDEEMED, EXPIRED y GRACE_PERIOD_EXPIRED. Facilitan la gestión del estado de los suscriptores. Los eventos SUBSCRIBED y PRICE_INCREASE son eventos mejorados de la primera versión.
Ahora las notificaciones tienen tipos, por lo que basta con una notificación para cualquier acción de un usuario para entender lo que ha ocurrido.
Tipos 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..."
}
}
Las notificaciones del servidor contienen información sobre una transacción y una renovación en el formato JWS que he descrito anteriormente.
Tienes que utilizar la URL del entorno Sandbox para probar las compras: https://api.storekit-sandbox.itunes.apple.com.
La nueva versión de las notificaciones del servidor aún no está disponible para ser probada. Una vez que esté disponible, será posible especificar diferentes URL para las notificaciones de Producción y Sandbox. Puedes elegir la V2 para Sandbox, y la V1 para Producción para las pruebas.
Además, App Store Connect permite ahora:
Apple ha mejorado significativamente el trabajo con las compras dentro de la aplicación y las suscripciones en la app en el lado del servidor. Desde mi punto de vista, estas son las novedades más útiles:
Cambiar a una nueva API no será difícil, basta con obtener el originalTransactionId para cada recibo. Es probable que ya esté contenida en tu base.
En todo caso, lo más difícil al integrar las suscripciones en una aplicación móvil es crear un sistema de análisis y optimizar la economía. Adapty puede solucionar bien estos problemas:
Más información sobre estas funciones, para implementar las suscripciones en tu aplicación más rápidamente y monetizar tu aplicación antes y mejor.
Further reading
Tutorial
septiembre 6, 2022
Tutorial
septiembre 6, 2022