Démarrage
-
Installez le package
Fenêtre de terminal npm i @capgo/native-purchasesFenêtre de terminal pnpm add @capgo/native-purchasesFenêtre de terminal yarn add @capgo/native-purchasesFenêtre de terminal bun add @capgo/native-purchases -
Synchronisez avec les projets natifs
Fenêtre de terminal npx cap syncFenêtre de terminal pnpm cap syncFenêtre de terminal yarn cap syncFenêtre de terminal bunx cap sync -
Vérifiez la prise en charge de la facturation
import { NativePurchases } from '@capgo/native-purchases';const { isBillingSupported } = await NativePurchases.isBillingSupported();if (!isBillingSupported) {throw new Error('Billing is not available on this device');} -
Chargez les produits directement depuis les boutiques
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émentez 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, // REQUIRED for Android subscriptions, ignored on iOSproductType: PURCHASE_TYPE.SUBS,quantity: 1,});console.log('Transaction ID', transaction.transactionId);await NativePurchases.restorePurchases();- Créez des produits intégrés et des abonnements dans App Store Connect.
- Utilisez StoreKit Local Testing ou les testeurs Sandbox pour les tests.
- Aucune modification du manifeste n’est requise. Assurez-vous que vos produits sont approuvés.
- Créez des produits intégrés et des abonnements dans Google Play Console.
- Téléchargez au moins une version de test interne et ajoutez des testeurs de licence.
- Ajoutez la permission de facturation à
AndroidManifest.xml:
<uses-permission android:name="com.android.vending.BILLING" /> - Créez des produits intégrés et des abonnements dans App Store Connect.
Exemple de service d’achat
Section titled “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, // REQUIRED for Android subscriptions 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 titled “Options d’achat requises”| Option | Plateforme | Description |
|---|---|---|
productIdentifier | iOS + Android | SKU/ID de produit configuré dans App Store Connect / Google Play Console. |
productType | Android uniquement | PURCHASE_TYPE.INAPP ou PURCHASE_TYPE.SUBS. Par défaut INAPP. Toujours définir sur SUBS pour les abonnements. |
planIdentifier | Abonnements Android | ID du plan de base de Google Play Console. Requis pour les abonnements, ignoré sur iOS et les achats intégrés. |
quantity | iOS | Uniquement pour les achats intégrés, par défaut 1. Android achète toujours un seul article. |
appAccountToken | iOS + Android | UUID/chaîne liant l’achat à votre utilisateur. Doit être un UUID sur iOS ; Android accepte toute chaîne obscurcie jusqu’à 64 caractères. |
isConsumable | Android | Définir sur true pour consommer automatiquement les jetons après avoir accordé le droit pour les consommables. Par défaut false. |
Vérification du statut des droits
Section titled “Vérification du statut des droits”Utilisez getPurchases() pour une vue multiplateforme de chaque transaction signalée par les boutiques :
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 titled “Comportement par plateforme”- iOS : Les abonnements incluent
isActive,expirationDate,willCancelet la prise en charge des écouteurs StoreKit 2. Les achats intégrés nécessitent une validation de reçu côté serveur. - Android :
isActive/expirationDatene sont pas renseignés ; appelez l’API Google Play Developer avec lepurchaseTokenpour obtenir le statut autoritaire.purchaseStatedoit êtrePURCHASEDetisAcknowledgeddoit êtretrue.
Référence rapide de l’API
Section titled “Référence rapide de l’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.purchaseProduct()– lancer le flux d’achat StoreKit 2 ou Billing client.restorePurchases()– rejouer les achats historiques et synchroniser sur 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 votre application (iOS uniquement).
Bonnes pratiques
Section titled “Bonnes pratiques”- Afficher les prix de la boutique – Apple exige d’afficher
product.titleetproduct.priceString; ne jamais coder en dur. - Utiliser
appAccountToken– générer de manière déterministe un UUID (v5) à partir de votre ID utilisateur pour lier les achats aux comptes. - Valider côté serveur – envoyer
receipt(iOS) /purchaseToken(Android) à votre backend pour vérification. - Gérer les erreurs avec élégance – vérifier les annulations utilisateur, les échecs réseau et les environnements de facturation non pris en charge.
- Tester minutieusement – suivre le guide sandbox iOS et le guide sandbox Android.
- Offrir la restauration et la gestion – ajouter des boutons d’interface utilisateur connectés à
restorePurchases()etmanageSubscriptions().
Dépannage
Section titled “Dépannage”Les produits ne se chargent pas
- Assurez-vous que l’ID de bundle / l’ID d’application correspond à la configuration de la boutique.
- Confirmez que les ID de produit 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 la boutique n’est pas instantanée.
Achat annulé ou bloqué
- Les utilisateurs peuvent annuler en cours de flux ; enveloppez les appels dans
try/catchet affichez des messages d’erreur conviviaux. - Pour Android, assurez-vous que les comptes de test installent l’application depuis Play Store (piste interne) pour que la facturation fonctionne.
- Vérifiez logcat/Xcode pour les erreurs de facturation lors de l’exécution sur l’appareil.
État d’abonnement incorrect
- Utilisez
getPurchases()pour comparer les données de la boutique avec votre cache de droits local. - Sur Android, interrogez toujours l’API Google Play Developer avec le
purchaseTokenpour obtenir les dates d’expiration ou le statut de remboursement. - Sur iOS, vérifiez
isActive/expirationDateet validez les reçus pour détecter les remboursements ou les révocations.