Compras Dentro de la Aplicación (IAP) de Unity
Espacio de nombres: UnityEngine.Purchasing | Seguridad: UnityEngine.Purchasing.Security
Paquete: com.unity.purchasing
Unity IAP tiene su propia ruta de inicialización mediante UnityIAPServices.StoreController() → store.Connect(). No requiere UnityServices.InitializeAsync(), pero pueden coexistir si tu proyecto utiliza otros servicios de UGS. Si Analytics está presente y se llama a InitializeAsync(), IAP enviará automáticamente eventos de transacción.
Antes de Empezar
Lee siempre references/pre-check.md primero. Este archivo escanea el proyecto en busca de paquetes IAP de terceros, Google Billing nativo y versiones existentes de Unity IAP, y luego dirige a la ruta correcta. No leas ningún otro archivo de referencia ni hagas cambios hasta que la ruta esté resuelta.
Referencias Detalladas
- Escaneo del proyecto y enrutamiento de rutas (leer primero): Ver references/pre-check.md
- Firmas de API y ejemplos de código: Ver references/api-notes.md
- Extensiones de plataforma (Apple, Google): Ver references/platform-notes.md
- Edición de
IAPProductCatalog.json(esquema, serialización decimal, actualización): Ver references/codeless-catalog.md - Migración de v4 a v5: Ver references/migration-v4-to-v5.md
- Conversión de Google BillingClient nativo a Unity IAP 5: Ver references/path-convert-native-google-billing.md
- Conversión de plugin iOS StoreKit nativo a Unity IAP 5: Ver references/path-convert-native-storekit.md
- Conversión de Essential Kit billing a Unity IAP 5: Ver references/convert-essentialkit.md
- UniPay (FLOBUK) — evaluación y guía: Ver references/convert-unipay.md
- RevenueCat — evaluación y guía de conversión: Ver references/convert-revenuecat.md
- Adapty — evaluación y guía de conversión: Ver references/convert-adapty.md
- Agregar Unity IAP 5 a un proyecto sin IAP existente: Ver references/path-add-iap-to-new-project.md
- Implementar capacidades IAP D2C (proveedor de pago de terceros — Stripe/Coda, requiere v5.4+): Ver references/path-implement-iap-d2c.md
Lee los archivos de referencia bajo demanda, solo cuando necesites firmas de API específicas, detalles de extensiones de plataforma o mapeos de migración.
Flujo de Inicialización
- Obtén
StoreControllermedianteUnityIAPServices.StoreController()(o servicios individuales medianteDefaultStore(),DefaultProduct(),DefaultPurchase()) - Suscríbete a todos los eventos requeridos (ver Suscripciones de Eventos Requeridas a continuación) antes de llamar a
Connect() await store.Connect()para conectar con la tienda de la plataforma- En
OnStoreConnected, llama astore.FetchProducts(List<ProductDefinition>)para cargar el catálogo - En
OnProductsFetched, los productos están listos para mostrarse y comprarse
Usa Awake() para la inicialización — asegura que IAP esté listo antes que otros métodos Start().
Tipos de producto: ProductType.Consumable, ProductType.NonConsumable, ProductType.Subscription.
Obtención de Productos
Define los productos como List<ProductDefinition> y pásalos a store.FetchProducts(). Usa StoreSpecificIds cuando los IDs de producto difieran entre las tiendas de Apple y Google. Para catálogos complejos, usa CatalogProvider para gestionar conjuntos de productos e IDs específicos de tienda.
| Método | Comportamiento |
|---|---|
GetProducts() | Devuelve la lista de productos en caché (síncrono, desactualizado si no se llamó a FetchProducts) |
FetchProducts() | Consulta a la tienda para obtener precios/disponibilidad actualizados y actualiza la caché |
GetProductById(id) | Devuelve un único producto en caché por ID |
NO son intercambiables. Siempre llama a FetchProducts() primero antes de confiar en GetProducts().
Flujo de Compra en Dos Pasos
IAP v5 usa un flujo obligatorio de dos pasos: Pendiente → Confirmar.
store.PurchaseProduct(product)— inicia el diálogo de compra de la plataforma- Se dispara
OnPurchasePending— recibes unPendingOrder - Valida el recibo y otorga el contenido al jugador
store.ConfirmPurchase(pendingOrder)— finaliza la transacción- Se dispara
OnPurchaseConfirmed— recibe el tipo baseOrder; usa coincidencia de patronesConfirmedOrder(éxito) vsFailedOrder(confirmación fallida)
DEBES llamar a ConfirmPurchase(pendingOrder) después de otorgar el contenido. Las compras no confirmadas se reenvían en el próximo inicio de la aplicación para evitar pérdidas de compras.
Desduplicación: OnPurchasePending puede dispararse múltiples veces para la misma compra (por ejemplo, reinicio de la aplicación antes de la confirmación). Siempre verifica si el contenido ya fue otorgado.
Consumibles: Las compras consumibles confirmadas NO son devueltas por FetchPurchases. Realiza tu propio seguimiento de las concesiones de consumibles (por ejemplo, en Cloud Save o Economy).
Compras diferidas: OnPurchaseDeferred se dispara para compras de Ask-to-Buy (iOS) y compras diferidas de Google Play. NO otorgues contenido — espera a OnPurchasePending cuando se apruebe.
Restauración de Transacciones
store.RestoreTransactions(callback) reenvía las compras no consumibles y de suscripción. Cada compra restaurada dispara OnPurchasePending.
Requerido en iOS para cumplir con la App Store de Apple — agrega un botón "Restaurar Compras".
Las suscripciones no renovables de Apple no se pueden restaurar mediante RestoreTransactions. Realiza su seguimiento en el servidor.
Validación de Recibos
| Plataforma | Enfoque |
|---|---|
| Google Play | CrossPlatformValidator con GooglePlayTangle.Data() — validación local compatible |
| Apple (StoreKit 2) | La validación local es una operación nula. Usa order.Info.Apple?.jwsRepresentation para validación del lado del servidor |
Genera datos de enredo mediante Services > In-App Purchasing > Receipt Validation Obfuscator en el Editor de Unity.
Verificación de Derechos
Úsalo cuando no tengas el Order y quieras conocer el estado de un producto específico (reemplaza product.hasReceipt de v4). Si ya tienes el Order, verifica su tipo: PendingOrder corresponde a EntitledUntilConsumed (consumibles) o EntitledButNotFinished (no consumibles/suscripciones), ConfirmedOrder corresponde a FullyEntitled.
Llama a store.CheckEntitlement(product) y maneja store.OnCheckEntitlement. Verifica que entitlement.Status == EntitlementStatus.FullyEntitled.
Valores de EntitlementStatus: FullyEntitled, EntitledUntilConsumed, EntitledButNotFinished, NotEntitled, Unknown.
Obtener Compras Existentes
store.FetchPurchases() recupera todas las compras actuales de la tienda. Útil al iniciar la aplicación.
| Método | Comportamiento |
|---|---|
GetPurchases() | Devuelve la lista de compras en caché |
FetchPurchases() | Consulta a la tienda las compras actuales y sobrescribe la lista en caché |
FetchPurchases() reemplaza toda la lista en caché en cada llamada. Solo se devuelven no consumibles y suscripciones.