React Native アプリ内課金とペイウォールの概要

0:02:00

RevenueCatのReact Native SDKコードラボへようこそ!

目標: このコードラボでは、RevenueCat React Native SDKを新しいReact Nativeアプリケーションに統合し、商品Offeringを取得し、事前構築されたネイティブペイウォールUIを表示する方法を学びます。

構築するもの:

読み込みインジケーターを表示し、RevenueCatから設定した「Offering」を取得し、RevenueCatUIペイウォールを表示するシンプルな1画面アプリ。

前提条件

開始する前に、以下を設定しておく必要があります:

  1. React Native環境: Node.js、React Native CLI、および必要なプラットフォーム固有のツールでReact Native開発環境が準備されていること。
  2. プラットフォーム要件:
iOS:最小デプロイメントターゲット13.4 Android:最小APIレベル23(バージョン6.0) React Nativeバージョン0.64以上
  1. RevenueCatアカウント: revenuecat.comで無料アカウント。
  2. App Store / Play Storeの設定:
App Store ConnectまたはGoogle Play Consoleで作成されたアプリ内商品(サブスクリプションまたは1回限りの購入)。Google Playの設定について詳しく知りたい場合は、コードラボ1:RevenueCat Google Play連携を確認してください。
  • RevenueCatダッシュボード内でこの商品がEntitlementOfferingにリンクされていること。これは最も重要なステップです。「Current」のOfferingがない場合、ペイウォールは表示されません。
  1. 物理デバイスまたは設定されたエミュレーター: アプリ内課金のテスト用。

このコードラボを終える頃には、React Nativeアプリにアプリ内課金を正常に実装し、RevenueCatのReact Native SDKを使用して動的なペイウォールを表示できるようになります。

overview

RevenueCat SDKのインポート

0:05:00

まず最初に、アプリ内課金を実装する前に、RevenueCat SDKを既存または新規プロジェクトにインポートする必要があります。開始するには、プロジェクトに以下の依存関係を追加します:

GitHubで最新リリースバージョンを確認できます。

インストール

npmを使用:

bash
npm install --save react-native-purchases

またはyarnを使用:

bash
yarn add react-native-purchases

プラットフォーム固有の設定

iOSセットアップ

iOSの場合、「In-App Purchase」機能を有効にする必要があります:

  1. Xcodeでプロジェクトを開く
  2. プロジェクトターゲットを選択
  3. 「Signing & Capabilities」に移動
  4. 「+ Capability」をクリックして「In-App Purchase」を追加

Androidセットアップ

Androidの場合、AndroidManifest.xmlに課金権限を追加します:

xml
<uses-permission android:name="com.android.vending.BILLING" />

また、AndroidManifest.xmlでActivityのlaunchModestandardまたはsingleTopに設定されていることを確認してください:

xml
<activity
  android:name=".MainActivity"
  android:launchMode="standard"
  ...
/>

RevenueCat SDKの初期化

次に、RevenueCat SDKを初期化しましょう。これはメインのApp.jsまたはApp.tsxファイルで行います。

  1. App.js(TypeScriptプロジェクトの場合はApp.tsx)を開く
  2. ファイルの先頭でSDKをインポート
  3. 定数にAPIキーを貼り付け
javascript
// App.js

import React, { useEffect, useState } from 'react';
import { Platform, View, Text, ActivityIndicator, StyleSheet } from 'react-native';
import Purchases from 'react-native-purchases';

// --- ここにREVENUECATキーを貼り付けてください ---
const androidApiKey = 'goog_YOUR_KEY_HERE';
const iosApiKey = 'appl_YOUR_KEY_HERE';

const App = () => {
  const [isConfigured, setIsConfigured] = useState(false);

  useEffect(() => {
    const initializePurchases = async () => {
      try {
        // 開発用にデバッグログを有効化
        Purchases.setLogLevel(Purchases.LOG_LEVEL.DEBUG);

        // 適切なAPIキーでSDKを設定
        if (Platform.OS === 'ios') {
          await Purchases.configure({ apiKey: iosApiKey });
        } else if (Platform.OS === 'android') {
          await Purchases.configure({ apiKey: androidApiKey });
        }

        console.log('RevenueCatの設定に成功しました!');
        setIsConfigured(true);
      } catch (e) {
        console.error('RevenueCat設定エラー:', e);
      }
    };

    initializePurchases();
  }, []);

  if (!isConfigured) {
    return (
      <View style={styles.centered}>
        <ActivityIndicator size="large" />
        <Text style={styles.loadingText}>RevenueCatを初期化中...</Text>
      </View>
    );
  }

  // メインアプリコンテンツは次のステップで追加されます
  return (
    <View style={styles.container}>
      <Text>RevenueCatの準備ができました!</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#fff',
  },
  centered: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  loadingText: {
    marginTop: 10,
    fontSize: 16,
  },
});

export default App;

useEffectフックを使用してRevenueCat SDKを初期化する基本的なReact Nativeアプリを作成しました。これにより、購入が行われる前にSDKが設定され準備が整っていることが保証されます。これは、最初から利用可能である必要があるプラグインを初期化する正しい方法です。

素晴らしい!これで実装の50%が完了しました。

Entitlementの検証

0:03:00

次に、ユーザーのEntitlementの検証に移りましょう。

前述の通り、Entitlementはユーザーが購入後にロック解除するアクセスレベルや機能を表します。これは、広告バナーを表示するかどうか、またはプレミアムアクセスを付与するかどうかを決定するのに役立ちます。

以下のコードスニペットを使用して、ユーザーがアクティブなEntitlementを持っているかどうかを簡単に確認できます:

javascript
const ENTITLEMENT_IDENTIFIER = ".."; // RevenueCatダッシュボードから特定のEntitlement識別子を取得

try {
  const customerInfo = await Purchases.getCustomerInfo();
  const isEntitled = customerInfo.entitlements.active[ENTITLEMENT_IDENTIFIER]?.isActive;

  if (isEntitled) {
    // ユーザーはこのEntitlementへのアクセスを持っています
    console.log('ユーザーは権限を持っています');
  } else {
    // ユーザーはアクセスを持っていません
    console.log('ユーザーは権限を持っていません');
  }
} catch (e) {
  console.error('Entitlement確認エラー:', e);
}

ユーザーが特定のEntitlementを持っているかどうかを確認したら、アプリのビジネスモデルに基づいてどのように進めるかを決定できます。

例えば、アプリが広告サポートの場合、AdMobバナーを表示または非表示にすることを選択できます。または、ペイウォールや購入ダイアログを表示して、ユーザーが高度な機能やコンテンツをロック解除できるようにすることもできます。

そのロジックを実装する方法の例を以下に示します:

javascript
if (isEntitled) {
  // ユーザーがこのEntitlementへのアクセスを付与されている場合、バナーを表示する必要はありません
} else {
  // ここでバナーUIを表示するか、ペイウォールを表示
}

アプリ内課金の実装

0:04:00

次に、広告なし体験を提供するためのアプリ内課金を実装しましょう。開始するには、まずRevenueCatダッシュボードから関連する商品情報を取得する必要があります。この商品データは、ユーザーに購入オプションを提示するために使用されます。

以下の例に示すように、Purchases.getProducts()を呼び出すことで利用可能な商品を取得できます:

javascript
// RevenueCatサーバーから商品情報を取得
const products = await Purchases.getProducts(['paywall_tester.subs']);

// アプリ内課金を進行
const purchaseResult = await Purchases.purchaseStoreProduct(products[0]);

paywall_tester.subs:weeklypaywall_tester.subs:monthlypaywall_tester.subs:yearlyなど、複数の商品バリエーションを提供している場合、productIdsフィールドの値としてベース商品識別子paywall_tester.subsを使用することで商品の取得を簡素化できます。これにより、RevenueCatはすべての関連商品バリエーションをリストとして取得し、ペイウォールUIで動的に提示できます。

商品データを取得したら、Purchases.purchaseStoreProduct(product)を呼び出すことでアプリ内課金フローを開始できます。これにより自動的にGoogle Play購入ダイアログまたはAppleの購入シートがトリガーされ、ユーザーはアプリ内でトランザクションを完了できます。

このように、わずか数行のコードで完全に機能するアプリ内課金フローを統合できました—レシート、ストアAPI、または購入検証を手動で処理する複雑さに対処する必要はありません。

完全なコード例は以下のようになります:

javascript
import Purchases from 'react-native-purchases';

/**
 * 特定の商品をIDで取得し、購入フローを開始します。
 *
 * この関数は、商品が見つからない、ユーザーが購入をキャンセルした、
 * またはその他のストアエラーなどの潜在的なエラーを処理します。
 */
const purchaseProduct = async () => {
  // 1. 取得したい商品識別子を定義
  const productId = 'paywall_tester.subs';

  try {
    // 2. RevenueCatからStoreProduct(s)を取得
    console.log('商品を取得中...');
    const products = await Purchases.getProducts([productId]);

    // 3. 商品リストが空でないか確認
    if (products.length === 0) {
      console.error('エラー:商品が見つかりません。IDとRevenueCatの設定を確認してください。');
      // オプションで、ユーザーにエラーメッセージを表示
      return;
    }

    const productToPurchase = products[0];
    console.log('商品が見つかりました:', productToPurchase.title, '。購入を開始します...');

    // 4. 購入フローを開始
    const { customerInfo } = await Purchases.purchaseStoreProduct(productToPurchase);

    // 5. Entitlementを確認して購入が成功したか確認
    // "your_premium_entitlement"をRevenueCatからの実際のEntitlement識別子に置き換えてください
    if (customerInfo.entitlements.active['your_premium_entitlement']?.isActive) {
      console.log('購入成功!ユーザーはプレミアムアクセスを持っています。');
      // プレミアムコンテンツへのアクセスを付与
    } else {
      console.log('購入完了しましたが、Entitlementがアクティブではありません。');
    }
  } catch (e) {
    // 6. 潜在的なエラーを処理
    if (e.code === Purchases.PURCHASES_ERROR_CODE.PURCHASE_CANCELLED_ERROR) {
      console.log('ユーザーによって購入がキャンセルされました。');
    } else {
      console.error('購入がエラーで失敗しました:', e.message);
    }
  }
};

ペイウォールの実装

0:07:00

次は、React Nativeでペイウォールを実装する時間です。

ステップ1:RevenueCatUIパッケージのインストール

まず、事前構築されたペイウォールコンポーネントを提供するRevenueCatUIパッケージをインストールします:

bash
npm install --save react-native-purchases-ui
# または
yarn add react-native-purchases-ui

ステップ2:RevenueCatUIのインポート

ファイルの先頭でペイウォール表示メソッドをインポートします:

javascript
import { presentPaywallIfNeeded } from 'react-native-purchases-ui';

ステップ3:Offeringの取得とペイウォールの表示

App.jsを更新してOfferingを取得し、ペイウォールを表示しましょう。既存のアプリコードを以下で置き換えます:

javascript
// App.js

import React, { useEffect, useState } from 'react';
import {
  Platform,
  View,
  Text,
  ActivityIndicator,
  StyleSheet,
  SafeAreaView,
} from 'react-native';
import Purchases from 'react-native-purchases';
import { presentPaywallIfNeeded } from 'react-native-purchases-ui';

// --- ここにREVENUECATキーを貼り付けてください ---
const androidApiKey = 'goog_YOUR_KEY_HERE';
const iosApiKey = 'appl_YOUR_KEY_HERE';

const App = () => {
  const [isConfigured, setIsConfigured] = useState(false);
  const [isLoading, setIsLoading] = useState(true);
  const [offering, setOffering] = useState(null);
  const [errorMessage, setErrorMessage] = useState(null);

  useEffect(() => {
    const initializePurchases = async () => {
      try {
        // 開発用にデバッグログを有効化
        Purchases.setLogLevel(Purchases.LOG_LEVEL.DEBUG);

        // 適切なAPIキーでSDKを設定
        if (Platform.OS === 'ios') {
          await Purchases.configure({ apiKey: iosApiKey });
        } else if (Platform.OS === 'android') {
          await Purchases.configure({ apiKey: androidApiKey });
        }

        console.log('RevenueCatの設定に成功しました!');
        setIsConfigured(true);
      } catch (e) {
        console.error('RevenueCat設定エラー:', e);
        setErrorMessage('RevenueCatの初期化に失敗しました');
        setIsLoading(false);
      }
    };

    initializePurchases();
  }, []);

  useEffect(() => {
    if (!isConfigured) return;

    const loadOfferings = async () => {
      try {
        setIsLoading(true);
        setErrorMessage(null);

        // RevenueCatから現在のOfferingを取得
        const offerings = await Purchases.getOfferings();

        if (offerings.current !== null) {
          setOffering(offerings.current);
        } else {
          setErrorMessage('現在のOfferingが見つかりません。RevenueCatダッシュボードを確認してください。');
        }
      } catch (e) {
        console.error('Offering取得エラー:', e);
        setErrorMessage(`Offeringの読み込みに失敗しました:${e.message}`);
      } finally {
        setIsLoading(false);
      }
    };

    loadOfferings();
  }, [isConfigured]);

  useEffect(() => {
    if (!offering) return;

    const showPaywall = async () => {
      try {
        const paywallResult = await presentPaywallIfNeeded({
          offering: offering,
        });

        console.log('ペイウォール結果:', paywallResult);

        if (paywallResult === Purchases.PAYWALL_RESULT.PURCHASED) {
          console.log('ユーザーが購入しました!');
        } else if (paywallResult === Purchases.PAYWALL_RESULT.RESTORED) {
          console.log('ユーザーが購入を復元しました!');
        } else if (paywallResult === Purchases.PAYWALL_RESULT.CANCELLED) {
          console.log('ユーザーがペイウォールをキャンセルしました');
        }
      } catch (e) {
        console.error('ペイウォール表示エラー:', e);
      }
    };

    showPaywall();
  }, [offering]);

  if (isLoading) {
    return (
      <SafeAreaView style={styles.centered}>
        <ActivityIndicator size="large" color="#6366f1" />
        <Text style={styles.loadingText}>ペイウォールを読み込み中...</Text>
      </SafeAreaView>
    );
  }

  if (errorMessage) {
    return (
      <SafeAreaView style={styles.centered}>
        <Text style={styles.errorText}>{errorMessage}</Text>
      </SafeAreaView>
    );
  }

  return (
    <SafeAreaView style={styles.container}>
      <Text style={styles.title}>RevenueCatペイウォールデモ</Text>
      <Text style={styles.subtitle}>ペイウォールが正常に表示されました!</Text>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#fff',
    padding: 20,
  },
  centered: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#fff',
  },
  loadingText: {
    marginTop: 16,
    fontSize: 16,
    color: '#666',
  },
  errorText: {
    fontSize: 16,
    color: '#ef4444',
    textAlign: 'center',
    padding: 20,
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 8,
    color: '#111',
  },
  subtitle: {
    fontSize: 16,
    color: '#666',
  },
});

export default App;
何をしたか?
  1. 読み込み状態、Offering、エラーメッセージを管理する状態変数を作成しました。
  2. コンポーネントがマウントされたときにまずRevenueCat SDKを初期化します。
  3. 設定が完了したら、Purchases.getOfferings()を使用してOfferingを取得します。
  4. Offeringが利用可能になったら、presentPaywallIfNeeded()を使用して自動的にペイウォールを表示します。
  5. 購入、復元、キャンセルを含むさまざまなペイウォール結果を処理します。

ステップ4:アプリケーションの実行

完了です!

デバイスまたはエミュレーターでアプリケーションを実行してください:

iOSの場合:
bash
npx react-native run-ios
Androidの場合:
bash
npx react-native run-android
以下が表示されるはずです:
  1. スピナー付きの「ペイウォールを読み込み中...」メッセージ。
  2. その後、下の画像のような完全に機能するネイティブペイウォールUI。
result

トラブルシューティング

ペイウォールが表示されない場合は、デバッグコンソールを確認し、これらの一般的な問題を確認してください: "現在のOfferingが見つかりません":これは最も一般的なエラーです。RevenueCatダッシュボードに「current」のOfferingがないことを意味します。Offeringsに移動し、Offeringを選択して、「current」としてマークされていることを確認してください。 不正なAPIキー:テストしているプラットフォームの正しいパブリックAPIキーをコピーしたことを再確認してください。 商品が設定されていない:ストアコンソールのアプリ内商品が正しく設定され、RevenueCatのEntitlementとOfferingにリンクされていることを確認してください。 サンドボックス/テストユーザーの問題:サンドボックステスターアカウント(iOS)でログインしているか、メールがライセンステスター(Android)として追加されていることを確認してください。 プラットフォーム固有の問題 iOS:XcodeでIn-App Purchase機能が有効になっていることを確認
  • Android:AndroidManifest.xmlにBILLING権限があることを確認

設定完了!🥳 これで、ユーザーが必要なEntitlementを持っていない場合に、ペイウォールエディターで設定したのとまったく同じデザインでペイウォールを表示できるようになります。

コードラボ:RevenueCat Google Play連携(ペイウォールの作成)で既に見たように、ペイウォールシステムはサーバードリブンUIに基づいて構築されています。これは、アプリの更新をプッシュしたり、レビュープロセスを経ることなく、ダッシュボードから直接ペイウォールのコンテンツとデザインを動的に更新できることを意味します。

まとめ

このコードラボでは、RevenueCatのReact Native SDKを統合し、アプリ内課金を実装し、React Nativeでペイウォールを構築する方法を学びました。さあ、アプリをリリースしてもっとお金を稼ぎましょう!💰

以下のリソースでRevenueCat SDKの使用についてさらに学ぶこともできます: