RORK LABEN
TOOLING — Rorkの開発者向けリポジトリが動き続けています。rork-xcodeが7月16日、rork-deviceが7月15日、rork-plistが7月13日に更新されましたOPUS46 — RorkでClaude Opus 4.6が稼働しています。Rork MaxはClaude Codeを土台にアプリを組み立てる設計ですSIM — ブラウザ上で動くクラウドのiOSシミュレータを備え、実機へのインストールは1クリック、App Storeへの提出は2クリックと案内されていますMAX — Rork MaxはReact Nativeではなく純粋なSwiftを出力します。iPhone・iPad・Apple Watch・Apple TV・Vision Pro、そしてiMessageまでが射程ですNATIVE — HealthKit、ARKitとLiDAR、NFC、Dynamic Island、Live Activities、Metalによる3D、Core MLのオンデバイス推論まで扱えますSEED — RorkはLeft Lane Capitalが主導する1,500万ドルのシードラウンドを実施し、Peak XVとa16z Speedrunが参加しましたTOOLING — Rorkの開発者向けリポジトリが動き続けています。rork-xcodeが7月16日、rork-deviceが7月15日、rork-plistが7月13日に更新されましたOPUS46 — RorkでClaude Opus 4.6が稼働しています。Rork MaxはClaude Codeを土台にアプリを組み立てる設計ですSIM — ブラウザ上で動くクラウドのiOSシミュレータを備え、実機へのインストールは1クリック、App Storeへの提出は2クリックと案内されていますMAX — Rork MaxはReact Nativeではなく純粋なSwiftを出力します。iPhone・iPad・Apple Watch・Apple TV・Vision Pro、そしてiMessageまでが射程ですNATIVE — HealthKit、ARKitとLiDAR、NFC、Dynamic Island、Live Activities、Metalによる3D、Core MLのオンデバイス推論まで扱えますSEED — RorkはLeft Lane Capitalが主導する1,500万ドルのシードラウンドを実施し、Peak XVとa16z Speedrunが参加しました
記事一覧/開発ツール
開発ツール/2026-04-14中級

Rork で課金後のステータスが反映されない — RevenueCat・StoreKit 同期問題のデバッグ手順

Rorkアプリで課金後にサブスクリプションが反映されない問題の原因と解決策を解説。RevenueCatのcustomerInfo取得タイミング・Entitlement設定・Sandbox遅延まで実例コード付きで解説します。

RevenueCat28StoreKit8サブスクリプション63課金8トラブルシューティング77Rork515

「購入ボタンを押したのに、プレミアム機能が使えない」——アプリ開発でこの問い合わせほど対応に困るものはありません。ユーザーは確かに課金しており、Stripe や App Store の管理画面にも購入履歴が残っています。なのに、アプリ側ではいつまでも「無料プラン」のままです。

この問題が生じる原因は1つではありません。RevenueCat の非同期処理のタイミング、StoreKit の Sandbox 特有の挙動、Entitlement ID の設定ミスなど、複数の要因が絡み合っています。ここではRork で RevenueCat を使った課金実装後に発生しやすい「ステータス同期問題」を、実際のデバッグ手順とコードを交えて整理します。

なぜ購入後にステータスが即座に反映されないのか

RevenueCat の customerInfo はリアルタイムではなく、キャッシュと非同期取得を組み合わせた仕組みで動作します。購入完了の直後に Purchases.shared.customerInfo() を呼び出しても、古いキャッシュが返ってくることがあります。

特に iOS の StoreKit を使っている場合、購入トランザクションの完了通知は以下の経路をたどります。

  1. ユーザーが購入ボタンをタップ
  2. App Store がトランザクションを処理(数秒〜数十秒かかる場合あり)
  3. RevenueCat の SDK がトランザクションを検知
  4. RevenueCat のサーバーに通知が送られ、Entitlement が更新される
  5. customerInfo が最新状態を返すようになる

問題の多くは 3〜5 のステップの間に UI 更新を試みることで発生します。

よくある原因 1:purchasePackage の直後に即座にステータス確認している

最も多いパターンです。以下のようなコードを書いていませんか?

// ❌ よくある間違い
const purchase = async () => {
  await Purchases.shared.purchasePackage(selectedPackage);
  // purchasePackage の完了直後に customerInfo を取得しても
  // 古いキャッシュが返ってくることがある
  const info = await Purchases.shared.getCustomerInfo();
  if (info.entitlements.active["premium"]) {
    navigateToPremiumFeature(); // ← 反映されていないため動かない場合がある
  }
};

正しくは、purchasePackage の戻り値を使います。purchasePackage は成功時に最新の CustomerInfo を含む結果を返すため、改めて getCustomerInfo を呼ぶ必要がありません。

// ✅ 正しい実装
const purchase = async () => {
  try {
    const { customerInfo } = await Purchases.shared.purchasePackage(selectedPackage);
    // purchasePackage の戻り値に最新の customerInfo が含まれている
    if (customerInfo.entitlements.active["premium"]) {
      navigateToPremiumFeature();
    }
  } catch (error) {
    if (error.code \!== PURCHASES_ERROR_CODE.PURCHASE_CANCELLED_ERROR) {
      console.error("購入エラー:", error.message);
    }
  }
};

よくある原因 2:Entitlement ID の名前が一致していない

RevenueCat の管理画面で設定した Entitlement ID と、コード内で参照している文字列が一致していない場合です。大文字・小文字、ハイフンとアンダースコアの違いも区別されます。

// ❌ 管理画面で "Premium" と設定しているのに小文字で参照
if (info.entitlements.active["premium"]) { ... }
 
// ✅ 管理画面の設定と完全一致させる
if (info.entitlements.active["Premium"]) { ... }

デバッグ時は console.log(JSON.stringify(info.entitlements.active)) で実際のキーを確認するのが確実です。

よくある原因 3:Sandbox 環境での更新遅延

開発・テスト時に Sandbox アカウントを使って購入している場合、Sandbox 環境は本番よりも処理が遅れることがあります。特に以下の場面で遅延が発生しやすいです。

  • Sandbox での定期購読の初回購入後(RevenueCat サーバーへの通知に数秒かかる場合がある)
  • Sandbox でのサブスクリプション更新(iOS Sandbox は更新間隔が短縮されているが、通知のタイミングがずれることがある)

テスト中に「動かない」と感じたら、まず数秒待ってから再試行してみてください。本番環境では発生しない場合も多くあります。

また、RevenueCat の Dashboard で Sandbox purchases タブを開き、購入データが届いているかを確認する習慣をつけましょう。購入データ自体が届いていなければ、SDK の設定(特に API キーが Sandbox 用かどうか)を見直す必要があります。

// iOS Sandbox 用の API キーと本番用の API キーを切り替える
const revenueCatApiKey = __DEV__
  ? "appl_YOUR_SANDBOX_API_KEY"  // Sandbox 用
  : "appl_YOUR_PRODUCTION_API_KEY"; // 本番用
 
await Purchases.configure({ apiKey: revenueCatApiKey });

よくある原因 4:customerInfo の更新リスナーを設定していない

RevenueCat SDK には、customerInfo が更新されたタイミングで通知を受け取るリスナーが用意されています。このリスナーを設定していないと、バックグラウンドで Entitlement が更新されても UI に反映されません。

// ✅ アプリ起動時にリスナーを設定する
import Purchases, { CustomerInfo } from "react-native-purchases";
 
// コンポーネントの useEffect などで設定
useEffect(() => {
  const listener = Purchases.addCustomerInfoUpdateListener(
    (info: CustomerInfo) => {
      // customerInfo が更新されるたびに呼ばれる
      const isPremium = \!\!info.entitlements.active["Premium"];
      setIsPremiumUser(isPremium);
    }
  );
 
  // クリーンアップ
  return () => {
    listener.remove();
  };
}, []);

このリスナーを使うことで、Webhook 経由でサブスクリプションが更新された場合でも自動的に UI が更新されます。

よくある原因 5:アプリの再起動後にサブスクリプション状態がリセットされる

これはローカル状態管理との組み合わせで起きるパターンです。useState だけで課金状態を管理している場合、アプリを再起動するとリセットされます。

アプリ起動時に必ず getCustomerInfo を呼び出して、最新の状態を取得するようにしましょう。

// ✅ アプリ起動時に常に customerInfo を確認する
const checkSubscriptionStatus = async () => {
  try {
    const info = await Purchases.shared.getCustomerInfo();
    const isPremium = \!\!info.entitlements.active["Premium"];
    setIsPremiumUser(isPremium);
  } catch (error) {
    // エラー時はオフラインを想定してキャッシュを使用
    console.warn("customerInfo の取得に失敗:", error.message);
  }
};
 
// App.tsx や useEffect の最初に呼び出す
useEffect(() => {
  checkSubscriptionStatus();
}, []);

デバッグのための簡易チェックリスト

課金後のステータスが反映されない場合、以下の順番で確認してみてください。

Step 1: RevenueCat Dashboard で購入データを確認する 管理画面 → Customers で該当ユーザーを検索し、購入データが届いているかを確認します。データがなければ SDK 設定の問題です。

Step 2: Entitlement ID を確認する console.log(JSON.stringify(info.entitlements.active)) でアクティブな Entitlement のキーを確認します。

Step 3: purchasePackage の戻り値を使っているか確認する 購入直後は purchasePackage の戻り値から customerInfo を取得します。

Step 4: リスナーが設定されているか確認する addCustomerInfoUpdateListener でリスナーを登録し、非同期更新を受け取れるようにします。

Step 5: アプリ起動時に getCustomerInfo を呼んでいるか確認する アプリの初期化処理で常に最新状態を取得します。

最後に

課金実装のバグは、ユーザーが実際に課金した後に発生するため、信頼の損失に直結します。「購入したのに使えない」という体験は、レビューへの悪影響やサポート工数の増加につながります。

RevenueCat の実装では、購入フローだけでなく、アプリ起動時・フォアグラウンド復帰時・Webhook 受信時のステータス確認を組み合わせる点が肝心です。上記のチェックリストで原因を特定できない場合は、RevenueCat の Customer Center ツールや SDK のデバッグログ(Purchases.setLogLevel(LOG_LEVEL.DEBUG))を活用してみてください。


課金実装の前に React Native の非同期処理を整理したい方にも役立ちます。

シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

開発ツール2026-06-14
Rork のサブスクを RevenueCat の Entitlement で組む — アクセス判定・Offering 駆動のペイウォール・復元の実装メモ
Rork(Expo)アプリの課金を RevenueCat で実装する際の設計メモです。Entitlement を唯一の真実とするアクセス判定、Offering 駆動でハードコードを避けるペイウォール、購入復元とリスナーの実装、サンドボックスで詰まりやすい点まで動くコードで整理します。
開発ツール2026-04-15
Rork × RevenueCat + Stripe Web 統合ガイド:iOS・Android・Web のサブスクリプションを1つのバックエンドで管理する
Rorkアプリで iOS StoreKit・Android Google Play Billing・Stripe Web の3つの課金チャネルを RevenueCat で一元管理する実装ガイド。クロスプラットフォーム対応の落とし穴と本番運用まで解説します。
開発ツール2026-06-25
機内モードで開くと有料会員にペイウォールが出る — RevenueCat の権限をオフラインでも保つキャッシュ設計
電波の弱い場所でアプリを開いた有料会員に、一瞬ペイウォールが見えてしまう。RevenueCat の customerInfo がオフライン起動で揺れる仕組みと、最後の正解を信頼期限つきでキャッシュして権限を維持する設計を、Expo アプリの動くコードで整理します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →