Commencer
-
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 -
Synchronisation 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 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');} -
Chargez les produits directement depuis les magasins
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);}); -
Mettre en œuvre des 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 et des abonnements intégrés à l’application dans App Store Connect.
- Utilisez les tests locaux StoreKit ou les testeurs Sandbox pour le contrôle qualité.
- Aucune modification du manifeste requise. Assurez-vous que vos produits sont approuvés.
- Créez des produits et des abonnements intégrés à l’application dans la console Google Play.
- Téléchargez au moins une version 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 intégrés à l’application 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”| Options | Plateforme | Descriptif |
|---|---|---|
productIdentifier | iOS + Android | SKU/ID de produit configuré dans la console App Store Connect / Google Play. |
productType | Android uniquement | PURCHASE_TYPE.INAPP ou PURCHASE_TYPE.SUBS. La valeur par défaut est INAPP. Toujours défini sur SUBS pour les abonnements. |
planIdentifier | Android abonnements | ID du plan de base de la console Google Play. Obligatoire pour les abonnements, ignoré sur iOS et les achats intégrés. |
quantity | iOS | Uniquement pour les achats intégrés, la valeur par défaut est 1. Android achète toujours un article. |
appAccountToken | iOS + Android | UUID/chaîne reliant l’achat à votre utilisateur. Il doit s’agir de l’UUID sur iOS ; Android accepte toute chaîne obscurcie jusqu’à 64 caractères. |
isConsumable | Android | Définissez sur true pour consommer automatiquement les jetons après avoir accordé le droit aux consommables. La valeur par défaut est 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 magasins :
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 de la plateforme
Section titled “Comportement de la 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 du reçu du serveur. - Android :
isActive/expirationDatene sont pas renseignés ; appelez le développeur Google Play API avec lepurchaseTokenpour obtenir le statut faisant autorité.purchaseStatedoit êtrePURCHASEDetisAcknowledgeddoit êtretrue.
API référence rapide- isBillingSupported() – vérifiez la disponibilité de StoreKit / Google Play.
Section titled “API référence rapide- isBillingSupported() – vérifiez la disponibilité de StoreKit / Google Play.”getProduct()/getProducts()– prix de récupération, titre localisé, description, offres d’introduction.purchaseProduct()– lancez le flux d’achat du client StoreKit 2 ou de facturation.restorePurchases()- relire l’historique des achats et synchroniser avec l’appareil actuel.getPurchases()– répertorie toutes les transactions iOS ou achats Play Billing.manageSubscriptions()– ouvre l’interface utilisateur native de gestion des abonnements.addListener('transactionUpdated')– gère les transactions StoreKit 2 en attente au démarrage de votre application (iOS uniquement).
## Bonnes pratiques
- Afficher les prix du magasin – Apple nécessite l’affichage de
product.titleetproduct.priceString; jamais de code en dur. - Utilisez
appAccountToken– générez de manière déterministe un UUID (v5) à partir de votre identifiant utilisateur pour lier les achats aux comptes. - Valider côté serveur – envoyez
receipt(iOS) /purchaseToken(Android) à votre backend pour vérification. - Gérez les erreurs avec élégance : vérifiez les annulations d’utilisateurs, les pannes de réseau et les environnements de facturation non pris en charge.
- Testez minutieusement – suivez le iOS guide du bac à sable et le Android guide du bac à sable.
- Offre de restauration et de gestion – ajoutez 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 du bundle / l’ID de l’application correspond à la configuration du magasin.
- Confirmez que les identifiants de produits sont actifs et approuvés (App Store) ou activés (Google Play).
- Attendre plusieurs heures après la création des produits ; la propagation du magasin n’est pas instantanée.
Achat annulé ou bloqué
- Les utilisateurs peuvent annuler le flux intermédiaire ; enveloppez les appels dans
try/catchet des messages d’erreur faciles à afficher. - Pour Android, assurez-vous que les comptes de test installent l’application à partir de 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 du magasin avec votre cache de droits local. - Le Android, interrogez toujours le développeur Google Play API avec le
purchaseTokenpour obtenir les dates d’expiration ou le statut du remboursement. - Le iOS, vérifiez
isActive/expirationDateet validez les reçus pour détecter les remboursements ou les révocations.