Primeros pasos
Copia un prompt de configuración con los pasos de instalación y la guía completa en markdown para este plugin.
Set up this Capacitor plugin in the project.
Use the package manager already used by the project.
Install these package(s): `@capgo/native-purchases`
Run the required Capacitor sync/update step after installation.
Read this markdown guide for the full setup steps: https://raw.githubusercontent.com/Cap-go/website/refs/heads/main/apps/docs/src/content/docs/docs/plugins/native-purchases/getting-started.mdx
Use that guide for platform-specific steps, native file edits, permissions, config changes, imports, and usage setup.
If that guide references other docs pages, read them too.
Instalación
Sección titulada “Instalación”Puedes usar nuestro setup asistido por IA para instalar el plugin. Añade las skills de Capgo a tu herramienta de IA con el siguiente comando:
npx skills add https://github.com/Cap-go/capgo-skills --skill capacitor-pluginsLuego usa el siguiente prompt:
Use the `capacitor-plugins` skill from `Cap-go/capgo-skills` to install the `@capgo/native-purchases` plugin in my project.Si prefieres la configuración manual, instala el plugin ejecutando estos comandos y sigue las instrucciones de cada plataforma:
-
Instala el paquete
Ventana de terminal bun add @capgo/native-purchases -
Sincroniza con proyectos nativos
Ventana de terminal bunx cap sync -
Comprobar soporte de facturación
import { NativePurchases } from '@capgo/native-purchases';const { isBillingSupported } = await NativePurchases.isBillingSupported();if (!isBillingSupported) {throw new Error('Billing is not available on this device');} -
Cargar productos directamente desde las tiendas
import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases';const { products } = await NativePurchases.getProducts({productIdentifiers: ['com.example.premium.monthly','com.example.premium.yearly','com.example.one_time_unlock'],productType: PURCHASE_TYPE.SUBS, // Use PURCHASE_TYPE.INAPP for one‑time products});products.forEach((product) => {console.log(product.title, product.priceString);}); -
Implementar flujos de compra y restauración
import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases';const monthlyPlanId = 'monthly-plan'; // Base Plan ID from Google Play Consoleconst transaction = await NativePurchases.purchaseProduct({productIdentifier: 'com.example.premium.monthly',planIdentifier: monthlyPlanId, // Android base plan id, required unless offerToken is passed; ignored on iOSproductType: PURCHASE_TYPE.SUBS,quantity: 1,});console.log('Transaction ID', transaction.transactionId);await NativePurchases.restorePurchases();- Crea productos y suscripciones in-app en App Store Connect.
- Usa StoreKit Local Testing o testers de Sandbox para QA.
- No hace falta editar el manifest. Asegúrate de que tus productos estén aprobados.
- Crea productos y suscripciones in-app en Google Play Console.
- Sube al menos un build de prueba interna y añade testers de licencia.
- Añade el permiso de billing a
AndroidManifest.xml:
<uses-permission android:name="com.android.vending.BILLING" /> - Crea productos y suscripciones in-app en App Store Connect.
Ejemplo de servicio de compra
Sección titulada “Ejemplo de servicio de compra”import { NativePurchases, PURCHASE_TYPE, Transaction } from '@capgo/native-purchases';import { Capacitor } from '@capacitor/core';
class PurchaseService { private premiumProduct = 'com.example.premium.unlock'; private monthlySubId = 'com.example.premium.monthly'; private monthlyPlanId = 'monthly-plan'; // Base Plan ID (Android only)
async initialize() { const { isBillingSupported } = await NativePurchases.isBillingSupported(); if (!isBillingSupported) throw new Error('Billing unavailable');
const { products } = await NativePurchases.getProducts({ productIdentifiers: [this.premiumProduct, this.monthlySubId], productType: PURCHASE_TYPE.SUBS, });
console.log('Loaded products', products);
if (Capacitor.getPlatform() === 'ios') { NativePurchases.addListener('transactionUpdated', (transaction) => { this.handleTransaction(transaction); }); } }
async buyPremium(appAccountToken?: string) { const transaction = await NativePurchases.purchaseProduct({ productIdentifier: this.premiumProduct, productType: PURCHASE_TYPE.INAPP, appAccountToken, });
await this.processTransaction(transaction); }
async buyMonthly(appAccountToken?: string) { const transaction = await NativePurchases.purchaseProduct({ productIdentifier: this.monthlySubId, planIdentifier: this.monthlyPlanId, // Android base plan id, required unless offerToken is passed productType: PURCHASE_TYPE.SUBS, appAccountToken, });
await this.processTransaction(transaction); }
async restore() { await NativePurchases.restorePurchases(); await this.refreshEntitlements(); }
async openManageSubscriptions() { await NativePurchases.manageSubscriptions(); }
private async processTransaction(transaction: Transaction) { this.unlockContent(transaction.productIdentifier); this.validateOnServer(transaction).catch(console.error); }
private unlockContent(productIdentifier: string) { // persist entitlement locally console.log('Unlocked', productIdentifier); }
private async refreshEntitlements() { const { purchases } = await NativePurchases.getPurchases({ productType: PURCHASE_TYPE.SUBS, }); console.log('Current purchases', purchases); }
private async handleTransaction(transaction: Transaction) { console.log('StoreKit transaction update:', transaction); await this.processTransaction(transaction); }
private async validateOnServer(transaction: Transaction) { await fetch('/api/validate-purchase', { method: 'POST', body: JSON.stringify({ transactionId: transaction.transactionId, receipt: transaction.receipt, purchaseToken: transaction.purchaseToken, }), }); }}Opciones de compra requeridas
Sección titulada “Opciones de compra requeridas”| Opción | Plataforma | Descripción |
|---|---|---|
productIdentifier | iOS + Android | SKU/Product ID configurado en App Store Connect / Google Play Console. |
productType | Solo Android | PURCHASE_TYPE.INAPP o PURCHASE_TYPE.SUBS. Por defecto es INAPP. Siempre se establece en SUBS para suscripciones. |
planIdentifier | Suscripciones de Android | Base Plan ID de Google Play Console (Product.identifier en una suscripción, no Product.planIdentifier). Obligatorio para suscripciones en Android a menos que offerToken se proporcione. Se ignora en iOS y en compras in-app. |
offerToken | Android | Token para una suscripción concreta o una oferta de pago único, de la misma getProducts() / getProduct() llamada de compra. Para una suscripción, tiene prioridad sobre planIdentifier. Un token que no coincida con ninguna oferta actual se rechaza. |
billingPlanType | Suscripciones de iOS | Plan de facturación de StoreKit para comprar. Usa 'monthly' para facturación mensual con compromiso de 12 meses cuando product.pricingTerms expone esa opción. |
quantity | iOS | Solo para compras in-app, por defecto es 1. Android siempre compra un solo ítem. |
appAccountToken | iOS + Android | UUID/string que vincula la compra con tu usuario. En iOS debe ser un UUID; Android acepta cualquier string ofuscado de hasta 64 caracteres. |
isConsumable | Android | Establecer en true para consumir tokens automáticamente tras otorgar el entitlement de consumibles. Por defecto es false. |
Verificación del estado del entitlement
Sección titulada “Verificación del estado del entitlement”Usa getPurchases() para una vista multiplataforma de cada transacción que reportan las tiendas:
import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases';
const { purchases } = await NativePurchases.getPurchases({ productType: PURCHASE_TYPE.SUBS,});
purchases.forEach((purchase) => { if (purchase.isActive && purchase.expirationDate) { console.log('iOS sub active until', purchase.expirationDate); }
const isAndroidIapValid = ['PURCHASED', '1'].includes(purchase.purchaseState ?? '') && purchase.isAcknowledged;
if (isAndroidIapValid) { console.log('Grant in-app entitlement for', purchase.productIdentifier); }});Comportamiento de la plataforma
Sección titulada “Comportamiento de la plataforma”- iOS: Las suscripciones incluyen
isActive,expirationDate,willCancel, y soporte para el listener de StoreKit 2. Las compras in-app requieren validación de recibos en el servidor. - Android:
isActive/expirationDateno se completan; llama a la API de Google Play Developer con elpurchaseTokenpara obtener el estado oficial.purchaseStatedebe serPURCHASEDyisAcknowledgeddebe sertrue.
Referencia rápida de API
Sección titulada “Referencia rápida de API”isBillingSupported()– comprueba la disponibilidad de StoreKit / Google Play.getProduct()/getProducts()– obtén el precio, el título localizado, la descripción, las ofertas de introducción y los términos de precios de iOS admitidos.purchaseProduct()– inicia el flujo de compra del cliente de StoreKit 2 o Billing, incluidos los planes de facturación con compromiso mensual de iOS.restorePurchases()– reprocesa las compras históricas y sincronízalas con el dispositivo actual.getPurchases()– lista todas las transacciones de iOS o las compras de Play Billing.manageSubscriptions()– abre la interfaz de gestión de suscripciones nativas.addListener('transactionUpdated')– gestiona las transacciones pendientes de StoreKit 2 al iniciar la app (solo iOS).
Buenas prácticas
Sección titulada “Mejores prácticas”- Mostrar precios de la tienda – Apple exige mostrar
product.titleyproduct.priceString; nunca los hardcodees. - Usa
appAccountToken– genera un UUID (v5) de forma determinista a partir del ID de usuario para vincular compras a cuentas. - Validar en el servidor – envía
receipt(iOS) /purchaseToken(Android) a tu backend para su verificación. - Maneja los errores de forma adecuada – verifica cancelaciones de usuario, fallos de red y entornos de facturación no compatibles.
- Prueba a fondo – sigue la guía de sandbox de iOS y guía de sandbox de Android.
- Ofrece restauración y gestión – añade botones en la UI conectados a
restorePurchases()ymanageSubscriptions().
Ruptura (tipos de TypeScript)
Sección titulada “Ruptura (tipos de TypeScript)”Product.subscriptionPeriod ahora es opcional. Android lo omite en ofertas prepago (no recurrentes), que solo tienen precio. Leer product.subscriptionPeriod.unit sin una comprobación es un error de TypeScript. Usa product.subscriptionPeriod?.unit. Los detalles están en Ofertas de suscripción de Android.
Próximos pasos de Revenue
Sección titulada “Próximos pasos de Revenue”Una vez que el flujo de compra funcione, usa el Estrategia de ingresos para planificar tu primer funnel de pago: alcance del producto, ASO, precios, ubicación del paywall, analíticas y feedback de churn.
Solución de problemas
Sección titulada “Solución de problemas”Los productos no cargan
- Asegúrate de que el bundle ID / application ID coincida con la configuración de la tienda.
- Confirma que los product IDs estén activos y aprobados (App Store) o activados (Google Play).
- Espera unas horas tras crear los productos; la propagación de la tienda no es instantánea.
Compra cancelada o bloqueada
- Users can cancel mid-flow; wrap calls in
try/catchy muestra mensajes de error amigables. - En Android, asegúrate de que las cuentas de prueba instalen la app desde Play Store (pista interna) para que Billing funcione.
- Revisa logcat/Xcode para ver errores de facturación al ejecutar en el dispositivo.
Estado de suscripción incorrecto
- Usa
getPurchases()para comparar los datos de la tienda con tu caché local de derechos. - En Android, consulta siempre la API de Google Play Developer con
purchaseTokenpara obtener fechas de expiración o el estado de reembolsos. - En iOS, verifica
isActive/expirationDatey valida los recibos para detectar reembolsos o revocaciones.
Continúa desde Getting Started
Sección titulada “Continúa desde Primeros pasos”Si estás usando Primeros pasos para planificar la aprobación y distribución en la tienda, conéctalo con Uso de @capgo/native-purchases para la capacidad nativa al usar @capgo/native-purchases, @capgo/capacitor-in-app-review para el detalle de implementación en @capgo/capacitor-in-app-review, Usando @capgo/capacitor-in-app-review para la capacidad nativa en «Usando @capgo/capacitor-in-app-review», @capgo/capacitor-native-market para el detalle de implementación en @capgo/capacitor-native-market, y Usando @capgo/capacitor-native-market para la capacidad nativa en «Usando @capgo/capacitor-native-market.»