Lompat ke konten

Mulai

  1. Instal paket

    Jendela terminal
    bun add @capgo/native-purchases
  2. Sinkron dengan proyek native

    Jendela terminal
    bunx cap sync
  3. Periksa dukungan billing

    import { NativePurchases } from '@capgo/native-purchases';
    const { isBillingSupported } = await NativePurchases.isBillingSupported();
    if (!isBillingSupported) {
    throw new Error('Billing is not available on this device');
    }
  4. Muat produk secara langsung dari toko

    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);
    });
  5. Implementasikan alur pembelian & pengembalian

    import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases';
    const monthlyPlanId = 'monthly-plan'; // Base Plan ID from Google Play Console
    const transaction = await NativePurchases.purchaseProduct({
    productIdentifier: 'com.example.premium.monthly',
    planIdentifier: monthlyPlanId, // REQUIRED for Android subscriptions, ignored on iOS
    productType: PURCHASE_TYPE.SUBS,
    quantity: 1,
    });
    console.log('Transaction ID', transaction.transactionId);
    await NativePurchases.restorePurchases();
    • Buat produk dalam aplikasi dan langganan di App Store Connect.
    • Gunakan StoreKit Local Testing atau Sandbox tester untuk QA.
    • Tidak perlu edit manifest. Pastikan produk Anda disetujui.
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,
}),
});
}
}
PilihanPlatformDeskripsi
productIdentifieriOS + AndroidSKU/Kode Produk yang telah dikonfigurasi di App Store Connect / Google Play Console.
productTypeHanya AndroidPURCHASE_TYPE.INAPP atau PURCHASE_TYPE.SUBS. Default ke INAPP. Selalu ditetapkan ke SUBS untuk langganan.
planIdentifierID Rencana Dasar dari Google Play Console. Diperlukan untuk langganan, diabaikan pada iOS dan pembelian dalam aplikasi.Langganan iOS
billingPlanTypeRencana pembayaran StoreKit untuk membeli. Gunakanuntuk pembayaran bulanan dengan komitmen 12 bulan ketika 'monthly' mengungkapkan opsi tersebut. product.pricingTerms iOS
quantityHanya untuk pembelian dalam aplikasi, default ke. Android selalu membeli satu item. 1__CAPGO_KEEP_0__
appAccountTokeniOS + AndroidUUID/string yang terkait pembelian dengan pengguna Anda. Diperlukan UUID pada iOS; Android menerima string yang diobfuskan hingga 64 karakter.
isConsumableAndroidDipilih true untuk mengonsumsi token secara otomatis setelah memberikan hak untuk konsumables. Default adalah false.

Gunakan getPurchases() untuk tampilan lintas platform dari setiap transaksi yang dilaporkan oleh toko:

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);
}
});
  • iOS: Langganan mencakup isActive, expirationDate, willCancel, dan dukungan pendengar StoreKit 2.
  • Pembelian dalam aplikasi memerlukan validasi bukti penerimaan server.: isActive/expirationDate are not populated; call the Google Play Developer API with the purchaseToken tidak diisi; hubungi pengembang Google Play dengan __CAPGO_KEEP_0__ untuk status otoritatif. purchaseState harus diisi PURCHASED dan isAcknowledged harus diisi true.
  • isBillingSupported() – periksa ketersediaan StoreKit / Google Play.
  • getProduct() / getProducts() – mengambil harga, judul yang disesuaikan, deskripsi, penawaran intro, dan istilah harga iOS yang didukung.
  • purchaseProduct() – memulai alur pembelian StoreKit 2 atau Billing klien, termasuk rencana pembayaran bulanan iOS.
  • restorePurchases() – merekam pembelian sejarah dan sinkron ke perangkat saat ini.
  • getPurchases() – menampilkan semua transaksi iOS atau pembelian Play Billing.
  • manageSubscriptions() – membuka antarmuka pengelolaan langganan native.
  • addListener('transactionUpdated') – mengatasi transaksi StoreKit 2 yang menunggu ketika aplikasi Anda dimulai (hanya iOS).
  1. Tampilkan harga toko – Apple memerlukan menampilkan product.title dan product.priceString; tidak pernah mengkodekan secara keras.
  2. Menggunakan – menghasilkan UUID (v5) secara deterministik dari ID pengguna untuk menghubungkan pembelian ke akun. appAccountToken Mengvalidasi di server – kirim
  3. (iOS) / (Android) ke backend Anda untuk verifikasi. receipt Menghadapi kesalahan dengan sopan – periksa pembatalan pengguna, kegagalan jaringan, dan lingkungan pembayaran yang tidak didukung. purchaseToken Menguji secara menyeluruh – ikuti panduan
  4. iOS sandbox dan
  5. __CAPGO_KEEP_0__ __CAPGO_KEEP_1__ __CAPGO_KEEP_2__ __CAPGO_KEEP_3__ Petunjuk Panduan Sandbox Android.
  6. Pulihkan dan Kelola Penawaran – tambahkan tombol UI yang terhubung ke restorePurchases() dan manageSubscriptions().

Langkah-Langkah Selanjutnya untuk Pendapatan

Judul Bagian “Langkah-Langkah Selanjutnya untuk Pendapatan”

Setelah alur pembelian berfungsi, gunakan Revenue Playbook untuk merencanakan funnel pembayaran pertama: ruang lingkup produk, ASO, harga, penempatan paywall, analisis, dan umpan balik pengurangan.

Produk Tidak Terisi

  • Pastikan ID bundle / ID aplikasi sesuai dengan konfigurasi toko.
  • Konfirmasi bahwa ID produk aktif dan disetujui (App Store) atau diaktifkan (Google Play).
  • Tunggu beberapa jam setelah membuat produk; penyebaran toko tidak instan.

Pembelian dibatalkan atau terjebak

  • Pengguna dapat membatalkan di tengah alur; tutup panggilan dengan try/catch dan permukaan pesan kesalahan yang ramah.
  • Untuk Android, pastikan akun uji instal aplikasi dari Play Store (track internal) agar Billing berfungsi.
  • Cek logcat/Xcode untuk kesalahan billing saat menjalankan pada perangkat.

Keadaan langganan salah

  • Gunakan getPurchases() untuk membandingkan data toko dengan cache hak milik lokal Anda.
  • Pada Android, selalu tanyakan ke Google Play Developer API dengan purchaseToken __CAPGO_KEEP_0__ untuk mendapatkan tanggal kedaluwarsa atau status pengembalian.
  • Pada iOS, cek isActive/expirationDate dan validasi struk pembayaran untuk mendeteksi pengembalian atau pembatalan.