__CAPGO_KEEP_0__ - __CAPGO_KEEP_1__ アプリ向けリアルタイム更新

はじめに

  1. パッケージをインストール

    ターミナルウィンドウ
    bun add @capgo/native-purchases
  2. ネイティブプロジェクトと同期

    ターミナルウィンドウ
    bunx cap sync
  3. 請求支援を確認

    import { NativePurchases } from '@capgo/native-purchases';
    const { isBillingSupported } = await NativePurchases.isBillingSupported();
    if (!isBillingSupported) {
    throw new Error('Billing is not available on this device');
    }
  4. ストアから直接製品を読み込む

    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. 購入および復元フローを実装

    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();
    • StoreKit Local Testing または Sandbox テスト者を使用して QA を実行します。
    • マニフェストの編集は必要ありません。製品が承認されていることを確認してください。
    • Google Play Console でインアプリ製品とサブスクリプションを作成します。
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,
}),
});
}
}
オプションプラットフォーム説明
productIdentifieriOS + AndroidApp Store Connect / Google Play Console で設定された SKU / 商品 ID。
productTypeAndroid 限定PURCHASE_TYPE.INAPP または PURCHASE_TYPE.SUBS. デフォルト値 INAPP. いつもは SUBS サブスクリプション用
planIdentifierAndroid サブスクリプションGoogle Play Console から取得する基本プラン ID。サブスクリプションの場合必須、iOS とインアプリ購入の場合無視
billingPlanTypeiOS サブスクリプションStoreKit の購入プランを指定。 'monthly' を使用すると、月額の課金と 12 か月のコミットメントが表示される product.pricingTerms iOS
quantityインアプリ購入の場合のみ、デフォルト値Android は常に 1 つのアイテムを購入する 1__CAPGO_KEEP_0__
appAccountTokeniOS + Android__CAPGO_KEEP_0__
isConsumableAndroidを設定 true を自動的に消費するようにする false.

自動的に消費するようにする

特権の消費可能なものの権限を付与した後

特権の消費可能なものの権限を付与した後 getPurchases() 特権の消費可能なものの権限を付与した後

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: サブスクリプションには isActive, expirationDate, willCancel,およびStoreKit 2リスナーサポートが含まれます。アプリ内購入にはサーバー受領証の検証が必要です。
  • Android: isActive/expirationDate は埋められていません。Google Play Developer APIに、 purchaseToken の権威あるステータスを確認してください。 purchaseStatePURCHASEDisAcknowledgedtrue.

API quick reference

API quick reference
  • isBillingSupported() セクションのタイトルは “__CAPGO_KEEP_0__ quick reference” – ストアキット / Google Playの利用可能性を確認してください。
  • getProduct() / getProducts() – Apple Store 価格を取得、ローカライズされたタイトル、説明、紹介オファー、およびサポートされているiOS価格条件。
  • purchaseProduct() – StoreKit 2またはBillingクライアント購入フローの開始、iOS月額コミットメント請求計画を含む。
  • restorePurchases() – 歴史的な購入を再生し、現在のデバイスにsyncする。
  • getPurchases() – iOSのすべての取引またはPlay Billing購入をリストする。
  • manageSubscriptions() – ネイティブのサブスクリプション管理UIを開く。
  • addListener('transactionUpdated') – アプリが起動したときにiOS専用のStoreKit 2取引を処理する。
  1. ストア価格を表示 – Appleは表示を必要とし、;ハードコードしないこと。 product.title – Appleは表示を必要とし、;ハードコードしないこと。 product.priceString– Appleは表示を必要とし、;ハードコードしないこと。
  2. 使用 appAccountToken – ユーザーIDからUUID (v5) を決定論的に生成して、購入をアカウントに紐付けます。
  3. サーバー側で検証 – (iOS) / (Android) をバックエンドに送信して検証します。 receipt エラーを柔軟に処理 purchaseToken – ユーザーのキャンセル、ネットワークの障害、非対応の請求環境を確認します。
  4. 徹底的なテスト – iOS のサンドボックス ガイドを参照してください
  5. – Android のサンドボックス ガイドを参照してください – Android のサンドボックス ガイドを参照してください – Android のサンドボックス ガイドを参照してください – Android のサンドボックス ガイドを参照してください Android サンドボックス ガイド.
  6. オファー 復元 & 管理 – UI ボタンを接続して追加 restorePurchases() そして manageSubscriptions().

購入フローが正常に動作する後、最初の有料チャネルを計画するために使用する Revenue Playbook 製品範囲、ASO、価格設定、壁の配置、分析、そして脱落フィードバック

製品が読み込まれない

  • bundle ID / アプリ ID がストアの設定と一致していることを確認してください。
  • 製品 ID が有効かつ承認済み (App Store) または有効化済み (Google Play) であることを確認してください。
  • 製品を作成した後数時間待ってください。ストアのプロパゲーションは即時ではありません。

購入がキャンセルされたり、途中で止まったりします

  • ユーザーは途中でキャンセルすることができます。呼び出しを try/catch で囲み、親切なエラーメッセージを表面化してください。
  • Android の場合、ビリングが機能するように、Play Store (内部トラック) からアプリをインストールするテストアカウントを確保してください。
  • デバイス上で実行している場合、ビリングエラーを確認するには logcat/Xcode を参照してください。

サブスクリプションの状態が不正です

  • を使用して、ストアデータとローカルエンタイトルメントキャッシュを比較してください。 getPurchases() Android の場合、常に Google Play Developer __CAPGO_KEEP_0__ に対して Google Play の開発者 API を使用してください。
  • On Android, always query the Google Play Developer API with the purchaseToken 期間切れの日付または払い戻しステータスを取得する。
  • iOSでは、 isActive/expirationDate 受け取りを検出または取り消しするために、受け取りを検証する。