Prise en main
Copiez un prompt de configuration incluant les étapes d'installation et le guide markdown complet pour ce 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.
Installation
Section intitulée « Installation »Vous pouvez utiliser notre configuration assistée par IA pour installer le plugin. Ajoutez les skills Capgo à votre outil d'IA avec la commande suivante :
npx skills add https://github.com/Cap-go/capgo-skills --skill capacitor-pluginsUtilisez ensuite le prompt suivant :
Use the `capacitor-plugins` skill from `Cap-go/capgo-skills` to install the `@capgo/native-purchases` plugin in my project.Si vous préférez une installation manuelle, installez le plugin en exécutant les commandes suivantes et suivez les instructions spécifiques à chaque plateforme ci-dessous :
-
Installer le package
Fenêtre de terminal bun add @capgo/native-purchases -
Synchroniser avec les projets natifs
Fenêtre de terminal bunx cap sync -
Vérifier le support de facturation
import { NativePurchases } from '@capgo/native-purchases';const { isBillingSupported } = await NativePurchases.isBillingSupported();if (!isBillingSupported) {throw new Error('Billing is not available on this device');} -
Charger les produits directement depuis les stores
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);}); -
Implémenter les flux d'achat et de restauration
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();- Créez des produits et des abonnements in-app dans App Store Connect.
- Utilisez StoreKit Local Testing ou des testeurs Sandbox pour la QA.
- Aucune modification du manifest n’est requise. Assurez-vous que vos produits sont approuvés.
- Créez des produits et des abonnements in-app dans Google Play Console.
- Envoyez au moins un build de test interne et ajoutez des testeurs de licence.
- Ajoutez l’autorisation de facturation à
AndroidManifest.xml:
<uses-permission android:name="com.android.vending.BILLING" /> - Créez des produits et des abonnements in-app dans App Store Connect.
Exemple de service d’achat
Section intitulée « Exemple de service d’achat »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, }), }); }}Options d'achat requises
Section intitulée « Options d’achat requises »| Option | Plateforme | Description |
|---|---|---|
productIdentifier | iOS + Android | SKU/identifiant de produit configuré dans App Store Connect / Google Play Console. |
productType | Android uniquement | PURCHASE_TYPE.INAPP ou PURCHASE_TYPE.SUBS. Valeur par défaut : INAPP. Toujours défini sur SUBS pour les abonnements. |
planIdentifier | Abonnements Android | Identifiant du plan de base depuis Google Play Console (Product.identifier sur un abonnement, pas sur Product.planIdentifier). Requis pour les abonnements Android, sauf si offerToken est fourni. Ignoré sur iOS et pour les achats in-app. |
offerToken | Android | Token pour un abonnement ou une offre ponctuelle précise, issu du même getProducts() / getProduct() appel d’achat. Pour un abonnement, il prend le pas sur planIdentifier. Un token qui ne correspond à aucune offre actuelle est rejeté. |
billingPlanType | Abonnements iOS | Plan de facturation StoreKit à acheter. Utilisez 'monthly' pour une facturation mensuelle avec un engagement de 12 mois lorsque product.pricingTerms propose cette option. |
quantity | iOS | Uniquement pour les achats in-app, valeur par défaut : 1. Android achète toujours un seul article. |
appAccountToken | iOS + Android | UUID/chaîne de caractères liant l’achat à votre utilisateur. Doit être un UUID sur iOS ; Android accepte toute chaîne obfusquée jusqu’à 64 caractères. |
isConsumable | Android | Définir sur true pour consommer automatiquement les tokens après l’octroi du droit pour les articles consommables. Valeur par défaut : false. |
Vérification du statut des droits
Section intitulée « Vérification de l’état du droit »Utiliser getPurchases() pour une vue multiplateforme de chaque transaction remontée par les stores :
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); }});Comportement par plateforme
Section intitulée « Comportement de la plateforme »- iOS : Les abonnements incluent
isActive,expirationDate,willCancel, ainsi que la prise en charge du listener StoreKit 2. Les achats in-app nécessitent une validation du reçu côté serveur. - Android:
isActive/expirationDatene sont pas renseignés ; appelez API Google Play Developer avec lepurchaseTokenpour obtenir le statut officiel.purchaseStatedoit êtrePURCHASEDetisAcknowledgeddoit êtretrue.
Référence rapide API
Section intitulée « Référence rapide API »isBillingSupported()– vérifier la disponibilité de StoreKit / Google Play.getProduct()/getProducts()– récupérer le prix, le titre localisé, la description, les offres d'introduction et les conditions tarifaires iOS prises en charge.purchaseProduct()– lancez le flux d'achat StoreKit 2 ou Billing client, incluant les plans d'abonnement mensuels sur iOS.restorePurchases()– rejouer les achats historiques et les synchroniser avec l'appareil actuel.getPurchases()– lister toutes les transactions iOS ou les achats Play Billing.manageSubscriptions()– ouvrir l'interface native de gestion des abonnements.addListener('transactionUpdated')– gérer les transactions StoreKit 2 en attente au démarrage de l'app (iOS uniquement).
Bonnes pratiques
Section intitulée « Bonnes pratiques »- Afficher les prix du store – Apple exige d’afficher
product.titleetproduct.priceString; ne jamais coder en dur. - Utiliser
appAccountToken– générez de manière déterministe un UUID (v5) à partir de l’ID utilisateur pour lier les achats aux comptes. - Valider côté serveur – envoyez
receipt(iOS) /purchaseToken(Android) vers votre backend pour vérification. - Gérer les erreurs avec élégance – vérifiez les annulations de l'utilisateur, les échecs réseau et les environnements de facturation non pris en charge.
- Testez à fond – suivez le guide du sandbox iOS et guide du sandbox Android.
- Restauration et gestion des offres – ajoutez des boutons UI reliés à
restorePurchases()etmanageSubscriptions().
Breaking (types TypeScript)
Section intitulée « Breaking (TypeScript typings) »Product.subscriptionPeriod est désormais facultatif. Android l’omet pour les offres prépayées (non récurrentes), qui n’ont qu’un prix. Lire product.subscriptionPeriod.unit sans vérification est une erreur TypeScript. Utilisez product.subscriptionPeriod?.unit. Les détails sont dans Offres d’abonnement Android.
Prochaines étapes avec Revenue
Section intitulée « Prochaines étapes Revenue »Une fois le flux d'achat fonctionnel, utilisez le Playbook revenus pour planifier votre premier tunnel d'acquisition payant : périmètre produit, ASO, tarifs, emplacement du paywall, analytics et feedback sur le churn.
Troubleshooting
Section intitulée « Dépannage »Les produits ne se chargent pas
- Vérifiez que le bundle ID / application ID correspond à la configuration du store.
- Confirmez que les ID de produits sont actifs et approuvés (App Store) ou activés (Google Play).
- Attendez plusieurs heures après la création des produits ; la propagation dans le store n'est pas instantanée.
Achat annulé ou bloqué
- Users can cancel mid-flow; wrap calls in
try/catchet d’afficher des messages d’erreur clairs. - Sur Android, assurez-vous que les comptes de test installent l’application depuis le Play Store (piste interne) pour que le Billing fonctionne.
- Vérifiez logcat/Xcode pour les erreurs de billing lors de l’exécution sur l’appareil.
État de l’abonnement incorrect
- Utiliser
getPurchases()pour comparer les données du store avec votre cache local d’entitlements. - Sur Android, interrogez toujours l’API Google Play Developer API avec
purchaseTokento obtain expiration dates or refund status. - Sur iOS, vérifiez
isActive/expirationDateet validez les reçus pour détecter les remboursements ou révocations.
Continuer depuis Getting Started
Section intitulée « Continuer après Prise en main »Si vous utilisez Prise en main pour planifier la validation et la distribution sur le store, connectez-l’à Utiliser @capgo/native-purchases pour la capacité native dans Utiliser @capgo/native-purchases @capgo/capacitor-in-app-review pour le détail d'implémentation dans @capgo/capacitor-in-app-review, Utiliser @capgo/capacitor-in-app-review pour la capacité native dans Utiliser @capgo/capacitor-in-app-review, @capgo/capacitor-native-market pour le détail d'implémentation dans @capgo/capacitor-native-market, et Utiliser @capgo/capacitor-native-market pour la capacité native dans Utiliser @capgo/capacitor-native-market.