---
title: "フローとペイウォールの表示 - React Native"
description: "Adapty を使って React Native アプリでフローとペイウォールをユーザーに表示します。"
---

<MethodPromo method="getFlow" label="Display flows and paywalls" />
フローまたはペイウォールをフローービルダーで作成した場合、ユーザーに表示するためのレンダリング処理をモバイルアプリのコードに実装する必要はありません。そのようなフローには、表示するコンテンツと表示方法の両方が含まれています。

始める前に、以下を確認してください：

1. [フローまたはペイウォールを作成](create-paywall)していること。
2. [プレースメント](placements)に追加していること。
3. [フローを取得してビューを準備](react-native-get-pb-paywalls)していること。

:::warning
このガイドは**フローおよびペイウォールビルダーで作成されたペイウォール**専用です。SDK v4.0以降が必要です。フローの表示方法はリモートコンフィグペイウォールとは異なります。

- **リモートコンフィグペイウォール**の表示については、[リモートコンフィグで設計されたペイウォールのレンダリング](present-remote-config-paywalls)を参照してください。

:::

Adapty React Native SDK では、フローとペイウォールを表示する方法が2つあります：

- **Reactコンポーネント**: アプリのアーキテクチャやナビゲーションシステムに組み込めるコンポーネントです。

- **モーダル表示**
## Reactコンポーネント \{#react-component\}

フローを既存のコンポーネントツリーに埋め込むには、React Nativeのコンポーネント階層に`AdaptyFlowView`コンポーネントを直接使用します。埋め込みコンポーネントを使うことで、アプリのアーキテクチャやナビゲーションシステムに統合できます。
:::tip
`AdaptyFlowView` コンポーネントは、レンダリング時（設定と画像の読み込み時）にビューを作成します。事前に読み込むには、アプリの早い段階で同じフローに対して [`createFlowView`](react-native-get-pb-paywalls#fetch-the-view-configuration) を呼び出してください。コンポーネントはキャッシュされたデータを再利用し、ダウンロードを待たずにレンダリングします。
:::
```typescript showLineNumbers title="React Native (TSX)"

function MyFlow({ flow }) {
  const flowParams = useMemo(() => ({
    loadTimeoutMs: 3000,
  }), []);

  const onCloseButtonPress = useCallback<FlowEventHandlers['onCloseButtonPress']>(() => {}, []);
  const onProductSelected = useCallback<FlowEventHandlers['onProductSelected']>((productId) => {}, []);
  const onPurchaseStarted = useCallback<FlowEventHandlers['onPurchaseStarted']>((product) => {}, []);
  const onPurchaseCompleted = useCallback<FlowEventHandlers['onPurchaseCompleted']>((purchaseResult, product) => {}, []);
  const onPurchaseFailed = useCallback<FlowEventHandlers['onPurchaseFailed']>((error, product) => {}, []);
  const onRestoreStarted = useCallback<FlowEventHandlers['onRestoreStarted']>(() => {}, []);
  const onRestoreCompleted = useCallback<FlowEventHandlers['onRestoreCompleted']>((profile) => {}, []);
  const onRestoreFailed = useCallback<FlowEventHandlers['onRestoreFailed']>((error) => {}, []);
  const onAppeared = useCallback<FlowEventHandlers['onAppeared']>(() => {}, []);
  const onError = useCallback<FlowEventHandlers['onError']>((error) => {}, []);
  const onLoadingProductsFailed = useCallback<FlowEventHandlers['onLoadingProductsFailed']>((error) => {}, []);
  const onUrlPress = useCallback<FlowEventHandlers['onUrlPress']>((url) => {}, []);
  const onCustomAction = useCallback<FlowEventHandlers['onCustomAction']>((actionId) => {}, []);
  const onWebPaymentNavigationFinished = useCallback<FlowEventHandlers['onWebPaymentNavigationFinished']>(() => {}, []);

  return (
    <AdaptyFlowView
      flow={flow}
      params={flowParams}
      style={styles.flow}
      onCloseButtonPress={onCloseButtonPress}
      onProductSelected={onProductSelected}
      onPurchaseStarted={onPurchaseStarted}
      onPurchaseCompleted={onPurchaseCompleted}
      onPurchaseFailed={onPurchaseFailed}
      onRestoreStarted={onRestoreStarted}
      onRestoreCompleted={onRestoreCompleted}
      onRestoreFailed={onRestoreFailed}
      onAppeared={onAppeared}
      onError={onError}
      onLoadingProductsFailed={onLoadingProductsFailed}
      onCustomAction={onCustomAction}
      onUrlPress={onUrlPress}
      onWebPaymentNavigationFinished={onWebPaymentNavigationFinished}
    />
  );
}
```

## モーダル表示 \{#modal-presentation\}

フローをスタンドアロン画面として表示するには、[`createFlowView`](react-native-get-pb-paywalls#fetch-the-view-configuration) メソッドで作成した `view` に対して `view.present()` メソッドを使用します。各 `view` は一度しか使用できません。再度フローを表示する必要がある場合は、`createFlowView` をもう一度呼び出して新しい `view` インスタンスを作成してください。

:::warning
同じ `view` を再作成せずに再利用することは禁止されています。`AdaptyUIError.viewAlreadyPresented` エラーが発生します。
:::
```typescript showLineNumbers title="React Native (TSX)"

const view = await createFlowView(flow);

// Optional: handle flow events (close, purchase, restore, etc)
// view.setEventHandlers({ ... });

try {
  await view.present();
} catch (error) {
  // handle the error
}
```

:::important
`setEventHandlers` を複数回呼び出すと、以前に設定したハンドラーが上書きされ、デフォルトおよび指定したイベントの既存ハンドラーがすべて置き換えられます。
:::
### iOSのプレゼンテーションスタイルを設定する \{#configure-ios-presentation-style\}

`present()` メソッドに `iosPresentationStyle` パラメータを渡すことで、iOS でのフローの表示方法を設定できます。このパラメータには `'full_screen'`（デフォルト）または `'page_sheet'` を指定できます。

```typescript showLineNumbers
try {
  await view.present({ iosPresentationStyle: 'page_sheet' });
} catch (error) {
  // handle the error
}
```
## 開発者定義タイマーを使用する \{#use-developer-defined-timer\}

モバイルアプリで開発者定義タイマーを使用するには、`timerId`（この例では `CUSTOM_TIMER_NY`）を使います。これは Adapty ダッシュボードで設定した開発者定義タイマーの **Timer ID** です。これにより、アプリはタイマーを正しい値（例：元日までの残り時間を現在時刻から引いた `13d 09h 03m 34s` のような形式）で動的に更新できます。
<Tabs>
<TabItem value="component" label="React component">
```typescript showLineNumbers title="React Native (TSX)"
const flowParams = {
  customTimers: { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) }
};

<AdaptyFlowView
  flow={flow}
  params={flowParams}
  // ... your event handlers
/>
```
</TabItem>
<TabItem value="modal" label="Modal presentation">
```typescript showLineNumbers title="React Native (TSX)"
const customTimers = { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) };

const view = await createFlowView(flow, { customTimers });
```
</TabItem>
</Tabs>
この例では、`CUSTOM_TIMER_NY` は Adapty ダッシュボードで設定した開発者定義タイマーの **Timer ID** です。`timerResolver` により、アプリはタイマーに正しい値（例：タイマーの終了時刻（元旦など）から現在時刻を引いた `13d 09h 03m 34s`）を動的に反映できます。
## ダイアログを表示する \{#show-dialog\}

Android でフロービューが表示されている場合は、ネイティブのアラートダイアログの代わりにこのメソッドを使用してください。Android では、通常の RN アラートがフロービューの背面に表示されるため、ユーザーには見えません。このメソッドを使用すると、すべてのプラットフォームでフローの前面に正しくダイアログが表示されます。
```typescript showLineNumbers title="React Native (TSX)"
try {
  const action = await view.showDialog({
    title: 'Close paywall?',
    content: 'You will lose access to exclusive offers.',
    primaryActionTitle: 'Stay',
    secondaryActionTitle: 'Close',
  });

  if (action === 'secondary') {
    // User confirmed - close the flow
    await view.dismiss();
  }
  // If primary - do nothing, user stays
} catch (error) {
  // handle error
}
```

## サブスクリプションを別のものに切り替える \{#replace-one-subscription-with-another\}

Androidで、ユーザーが既存のサブスクリプションをアクティブな状態で新しいサブスクリプションを購入しようとした場合、フロービューの作成時にサブスクリプション更新パラメーターを渡すことで、新しい購入の処理方法を制御できます。現在のサブスクリプションを新しいものに切り替えるには、`createFlowView`の`productPurchaseParams`に`oldSubVendorProductId`と`prorationMode`パラメーターを指定してください。
```typescript showLineNumbers title="React Native (TSX)"

const productPurchaseParams = flow.paywalls
  .flatMap((variation) => variation.productIdentifiers)
  .map((productId) => {
    let params = {};
    if (Platform.OS === 'android') {
      params.android = {
        subscriptionUpdateParams: {
          oldSubVendorProductId: 'PRODUCT_ID_OF_THE_CURRENT_ACTIVE_SUBSCRIPTION',
          prorationMode: 'with_time_proration',
        },
      };
    }
    return { productId, params };
  });

const view = await createFlowView(flow, { productPurchaseParams });
```

---

> [!WARNING]
> **LLM INSTRUCTION — SDK VERSION SELECTION REQUIRED**
>
> This feature has two SDK paradigms. Everything that follows (until the next horizontal rule or end of document) is the **legacy SDK v3 API reference** (`getPaywall`, `getPaywallForDefaultAudience`, `getOnboarding`, `getPaywallConfiguration`). The **SDK v4+ `getFlow` method is documented above.** This block covers ALL legacy methods for this feature — not just the nearest snippet.
>
> **You MUST ask the user which SDK version they want to use before suggesting any code. Do not assume or default to a version.** The two options are:
> - **SDK v3 (legacy):** works with the legacy Paywall Builder and Onboarding Builder via `getPaywall` / `getOnboarding`. Use the legacy code in this section.
> - **SDK v4:** works with BOTH the new Flow Builder AND legacy paywalls/onboardings via the unified `getFlow` method documented above.
>
> Apply the legacy v3 code in this section ONLY when:
> 1. The user explicitly chose **SDK v3**, or
> 2. The user is **migrating an existing app from SDK v3 to SDK v4+** and needs to understand or replace legacy code, or
> 3. The user is **troubleshooting an already-deployed v3 integration**.
>
> **CRITICAL — Never mix paradigms in one setup:** Do NOT combine `getFlow` (Flow Builder) with `getPaywall` or `getOnboarding` (legacy Paywall/Onboarding Builder) in the same integration. These are incompatible patterns. Mixing them will produce inconsistent behavior and is unsupported.

ペイウォールビルダーを使用してペイウォールをカスタマイズした場合、ユーザーに表示するためにモバイルアプリのコードでレンダリングする必要はありません。このようなペイウォールには、ペイウォール内に表示する内容とその表示方法の両方が含まれています。

始める前に、以下を確認してください：

1. [ペイウォールを作成](create-paywall)している。
2. ペイウォールを[プレースメント](placements)に追加している。
3. [ペイウォールをフェッチしてビューを準備](react-native-get-pb-paywalls)している。

:::warning
このガイドは、SDK v3.0 以降が必要な**新しいペイウォールビルダーのペイウォール**専用です。ペイウォールの表示方法は、ペイウォールビルダーのバージョンやリモートコンフィグのペイウォールによって異なります。

- **リモートコンフィグのペイウォール**を表示する方法については、[リモートコンフィグで設計されたペイウォールのレンダリング](present-remote-config-paywalls)を参照してください。

:::

Adapty React Native SDK には、ペイウォールを表示する方法が 2 つあります：

- **React コンポーネント**: アプリのアーキテクチャやナビゲーションシステムに組み込めるコンポーネントです。

- **モーダル表示**
## Reactコンポーネント \{#react-component\}

:::note
**Reactコンポーネント**アプローチを使用するには、SDK 3.14.0以降が必要です。
:::

既存のコンポーネントツリー内にペイウォールを埋め込むには、React Nativeのコンポーネント階層の中で`AdaptyPaywallView`コンポーネントを直接使用します。埋め込みコンポーネントを使うことで、アプリのアーキテクチャやナビゲーションシステムに組み込むことができます。
:::note
Androidでは、ペイウォールがステータスバーの背後まで拡張されていない場合、ペイウォールの上部にビジュアルオーバーレイが表示されることがあります。ペイウォールではこれをオフにすることをお勧めします。[ペイウォール上部のビジュアルオーバーレイ（Android）](#visual-overlay-at-the-top-of-the-paywall-android)をご覧ください。
:::
```typescript showLineNumbers title="React Native (TSX)"

function MyPaywall({ paywall }) {
  const paywallParams = useMemo(() => ({
    loadTimeoutMs: 3000,
  }), []);

  const onCloseButtonPress = useCallback<EventHandlers['onCloseButtonPress']>(() => {}, []);
  const onProductSelected = useCallback<EventHandlers['onProductSelected']>((productId) => {}, []);
  const onPurchaseStarted = useCallback<EventHandlers['onPurchaseStarted']>((product) => {}, []);
  const onPurchaseCompleted = useCallback<EventHandlers['onPurchaseCompleted']>((purchaseResult, product) => {}, []);
  const onPurchaseFailed = useCallback<EventHandlers['onPurchaseFailed']>((error, product) => {}, []);
  const onRestoreStarted = useCallback<EventHandlers['onRestoreStarted']>(() => {}, []);
  const onRestoreCompleted = useCallback<EventHandlers['onRestoreCompleted']>((profile) => {}, []);
  const onRestoreFailed = useCallback<EventHandlers['onRestoreFailed']>((error) => {}, []);
  const onPaywallShown = useCallback<EventHandlers['onPaywallShown']>(() => {}, []);
  const onRenderingFailed = useCallback<EventHandlers['onRenderingFailed']>((error) => {}, []);
  const onLoadingProductsFailed = useCallback<EventHandlers['onLoadingProductsFailed']>((error) => {}, []);
  const onUrlPress = useCallback<EventHandlers['onUrlPress']>((url) => {}, []);
  const onCustomAction = useCallback<EventHandlers['onCustomAction']>((actionId) => {}, []);
  const onWebPaymentNavigationFinished = useCallback<EventHandlers['onWebPaymentNavigationFinished']>(() => {}, []);

  return (
    <AdaptyPaywallView
      paywall={paywall}
      params={paywallParams}
      style={styles.paywall}
      onCloseButtonPress={onCloseButtonPress}
      onProductSelected={onProductSelected}
      onPurchaseStarted={onPurchaseStarted}
      onPurchaseCompleted={onPurchaseCompleted}
      onPurchaseFailed={onPurchaseFailed}
      onRestoreStarted={onRestoreStarted}
      onRestoreCompleted={onRestoreCompleted}
      onRestoreFailed={onRestoreFailed}
      onPaywallShown={onPaywallShown}
      onRenderingFailed={onRenderingFailed}
      onLoadingProductsFailed={onLoadingProductsFailed}
      onCustomAction={onCustomAction}
      onUrlPress={onUrlPress}
      onWebPaymentNavigationFinished={onWebPaymentNavigationFinished}
    />
  );
}
```

## モーダル表示 \{#modal-presentation\}

ペイウォールをスタンドアロン画面として表示するには、[`createPaywallView`](react-native-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) メソッドで作成した `view` に対して `view.present()` メソッドを呼び出します。各 `view` は一度しか使用できません。ペイウォールを再度表示する必要がある場合は、`createPaywallView` をもう一度呼び出して新しい `view` インスタンスを作成してください。

:::warning
同じ `view` を再作成せずに再利用することは禁止されています。`AdaptyUIError.viewAlreadyPresented` エラーが発生します。
:::
```typescript showLineNumbers title="React Native (TSX)"

const view = await createPaywallView(paywall);

// Optional: handle paywall events (close, purchase, restore, etc)
// view.setEventHandlers({ ... });

try {
  await view.present();
} catch (error) {
  // handle the error
}
```

:::important
`setEventHandlers` を複数回呼び出すと、指定したハンドラーで既存のハンドラーが上書きされます。デフォルトのハンドラーと以前に設定したハンドラーの両方が、対象のイベントについて置き換えられます。
:::
### iOS のプレゼンテーションスタイルを設定する \{#configure-ios-presentation-style\}

`present()` メソッドに `iosPresentationStyle` パラメーターを渡すことで、iOS でのペイウォールの表示方法を設定できます。このパラメーターには `'full_screen'`（デフォルト）または `'page_sheet'` を指定できます。

```typescript showLineNumbers
try {
  await view.present({ iosPresentationStyle: 'page_sheet' });
} catch (error) {
  // handle the error
}
```
## 開発者定義タイマーを使用する \{#use-developer-defined-timer\}

モバイルアプリで開発者定義タイマーを使用するには、`timerId`（この例では `CUSTOM_TIMER_NY`）を使います。これは Adapty ダッシュボードで設定した開発者定義タイマーの **Timer ID** です。これにより、アプリはタイマーを正しい値（例：`13d 09h 03m 34s`、タイマーの終了時刻（元日など）から現在時刻を引いた値）で動的に更新できます。
<Tabs>
<TabItem value="component" label="React component">
```typescript showLineNumbers title="React Native (TSX)"
const paywallParams = {
  customTimers: { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) }
};

<AdaptyPaywallView
  paywall={paywall}
  params={paywallParams}
  // ... your event handlers
/>
```
</TabItem>
<TabItem value="modal" label="Modal presentation">
```typescript showLineNumbers title="React Native (TSX)"
const customTimers = { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) };

const view = await createPaywallView(paywall, { customTimers });
```
</TabItem>
</Tabs>
この例では、`CUSTOM_TIMER_NY` は Adapty ダッシュボードで設定した開発者定義タイマーの **Timer ID** です。`timerResolver` により、アプリはタイマーの終了時刻（元旦など）から現在時刻を引いた値として `13d 09h 03m 34s` のような正確な値でタイマーを動的に更新します。
## ダイアログを表示する \{#show-dialog\}

Android でペイウォールビューが表示されている場合、ネイティブのアラートダイアログの代わりにこのメソッドを使用してください。Android では、通常の RN アラートがペイウォールビューの背後に表示されるため、ユーザーには見えません。このメソッドを使用することで、すべてのプラットフォームでペイウォールの前面にダイアログが正しく表示されます。
```typescript showLineNumbers title="React Native (TSX)"
try {
  const action = await view.showDialog({
    title: 'Close paywall?',
    content: 'You will lose access to exclusive offers.',
    primaryActionTitle: 'Stay',
    secondaryActionTitle: 'Close',
  });

  if (action === 'secondary') {
    // User confirmed - close the paywall
    await view.dismiss();
  }
  // If primary - do nothing, user stays
} catch (error) {
  // handle error
}
```

## 別のサブスクリプションへの切り替え \{#replace-one-subscription-with-another\}

Androidで、ユーザーが既存のサブスクリプションを有効な状態で新しいサブスクリプションを購入しようとする場合、ペイウォールビューの作成時にサブスクリプション更新パラメータを渡すことで、新しい購入の処理方法を制御できます。現在のサブスクリプションを新しいサブスクリプションに切り替えるには、`createPaywallView` の `productPurchaseParams` に `oldSubVendorProductId` と `prorationMode` パラメータを指定してください。
```typescript showLineNumbers title="React Native (TSX)"

const productPurchaseParams = paywall.productIdentifiers.map((productId) => {
  let params = {};
  if (Platform.OS === 'android') {
    params.android = {
      subscriptionUpdateParams: {
        oldSubVendorProductId: 'PRODUCT_ID_OF_THE_CURRENT_ACTIVE_SUBSCRIPTION',
        prorationMode: 'with_time_proration',
      },
    };
  }
  return { productId, params };
});

const view = await createPaywallView(paywall, { productPurchaseParams });
```

## トラブルシューティング \{#troubleshooting\}
### ペイウォール上部のビジュアルオーバーレイ（Android） \{#visual-overlay-at-the-top-of-the-paywall-android\}

:::note
この設定は React Native SDK 3.15.5 以降でサポートされており、ベア React Native プロジェクトでのみ利用できます。

Expo managed workflow を使用している場合、この Android リソースを直接追加することはできません。この設定を適用するには、対応する Android リソースを追加するカスタム Expo config プラグインを作成し、app.config.js に登録する必要があります。これは Expo がネイティブ Android プロジェクトを管理しているため必須です。
:::
`AdaptyPaywallView` がステータスバーの後ろまで拡張されていない場合でも、その上部にビジュアルオーバーレイが表示されることがあります。これを削除するには、アプリに次のブールリソースを追加してください：

1. `android/app/src/main/res/values` に移動します。`bools.xml` ファイルがない場合は作成してください。

2. 次のリソースを追加します：

```xml
<resources>
    <bool name="adapty_paywall_enable_safe_area_paddings">false</bool>
</resources>
```

この変更はアプリ内のすべてのペイウォールにグローバルに適用されることに注意してください。

---