---
title: "在 React Native SDK 中展示用户引导"
description: "了解如何在 React Native 中展示用户引导，以提升转化率和收入。"
---

:::warning
**用户引导功能在 SDK v4 中已弃用，将在未来版本中移除。** 该功能不再接受修复或改进。请改用 [flows](react-native-get-pb-paywalls)：与在 WebView 中运行的用户引导不同，flows 直接在设备上进行原生渲染——带来更流畅的动画、一致的原生外观体验、更快的加载速度，以及无需 WebView 运行时依赖。请参阅 [获取 flows 和付费墙](react-native-get-pb-paywalls) 和 [展示 flows 和付费墙](react-native-present-paywalls) 以开始使用。
:::
如果你使用编辑工具自定义了用户引导，就无需在移动端代码中手动处理渲染逻辑来向用户展示它。这类用户引导已经包含了展示内容和展示方式的完整配置。

开始之前，请确认：

1. 已安装 [Adapty React Native SDK](sdk-installation-reactnative) 3.8.0 或更高版本。
2. 已[创建用户引导](create-onboarding)。
3. 已将用户引导添加到[版位](placements)。

Adapty React Native SDK 提供两种展示用户引导的方式：
- **React 组件**：嵌入式组件，可将其集成到应用的架构和导航系统中。

- **模态呈现**
## React 组件 \{#react-component\}

如需将用户引导嵌入现有组件树，可在 React Native 组件层级中直接使用 `AdaptyOnboardingView` 组件。嵌入式组件让你能够将其集成到应用的架构和导航系统中。

:::note
在 Android 上，我们建议对 `AdaptyOnboardingView` 进行额外配置，以避免视觉渲染异常。详见[系统界面遮挡 Android 用户引导内容](#system-ui-overlaps-onboarding-content-on-android)。
:::
<Tabs groupId="version" queryString>
<TabItem value="new" label="SDK 版本 3.14 或更高" default>
```typescript showLineNumbers title="React Native (TSX)"

function MyOnboarding({ onboarding }) {
  const onAnalytics = useCallback<OnboardingEventHandlers['onAnalytics']>((event, meta) => {}, []);
  const onClose = useCallback<OnboardingEventHandlers['onClose']>((actionId, meta) => {}, []);
  const onCustom = useCallback<OnboardingEventHandlers['onCustom']>((actionId, meta) => {}, []);
  const onPaywall = useCallback<OnboardingEventHandlers['onPaywall']>((actionId, meta) => {}, []);
  const onStateUpdated = useCallback<OnboardingEventHandlers['onStateUpdated']>((action, meta) => {}, []);
  const onFinishedLoading = useCallback<OnboardingEventHandlers['onFinishedLoading']>((meta) => {}, []);
  const onError = useCallback<OnboardingEventHandlers['onError']>((error) => {}, []);

  return (
    <AdaptyOnboardingView
      onboarding={onboarding}
      style={styles.container}
      onAnalytics={onAnalytics}
      onClose={onClose}
      onCustom={onCustom}
      onPaywall={onPaywall}
      onStateUpdated={onStateUpdated}
      onFinishedLoading={onFinishedLoading}
      onError={onError}
    />
  );
}
```
</TabItem>
<TabItem value="old" label="SDK 版本 < 3.14" default>
```typescript showLineNumbers title="React Native (TSX)"

function MyOnboarding({ onboarding }) {
  return (
    <AdaptyOnboardingView
      onboarding={onboarding}
      style={{ flex: 1 }}
      eventHandlers={{
        onAnalytics(event, meta) { 
          // Handle analytics events
        },
        onClose(actionId, meta) { 
          // Handle close actions
        },
        onCustom(actionId, meta) { 
          // Handle custom actions
        },
        onPaywall(actionId, meta) { 
          // Handle paywall actions
        },
        onStateUpdated(action, meta) { 
          // Handle state updates
        },
        onFinishedLoading(meta) { 
          // Handle when onboarding finishes loading
        },
        onError(error) { 
          // Handle errors
        },
      }}
    />
  );
}
```
</TabItem>
</Tabs>
## 模态展示 \{#modal-presentation\}

要将用户引导作为独立页面展示并允许用户关闭，请对 `createOnboardingView` 方法创建的 `view` 调用 `view.present()` 方法。每个 `view` 只能使用一次。如果需要再次展示用户引导，请重新调用 `createOnboardingView` 创建新的 `view` 实例。

:::warning
禁止在不重新创建的情况下复用同一个 `view`，否则会导致 `AdaptyUIError.viewAlreadyPresented` 错误。
:::
<Tabs groupId="version" queryString>
<TabItem value="new" label="SDK version 3.14 or later" default>
```typescript showLineNumbers title="React Native (TSX)"

const view = await createOnboardingView(onboarding);

// Optional: handle onboarding events (close, custom actions, etc)
// view.setEventHandlers({ ... });

try {
    await view.present();
} catch (error) {
    // handle the error
}
```
</TabItem>
<TabItem value="old" label="SDK 版本 < 3.14" default>
```typescript showLineNumbers title="React Native (TSX)"

const view = await createOnboardingView(onboarding);

view.setEventHandlers(); // handle close press, etc

try {
    await view.present();
} catch (error) {
    // handle the error
}
```
</TabItem>
</Tabs>
### 配置 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
}
```
## 用户引导加载动画 \{#loader-during-onboarding\}

在 React Native 中展示用户引导时，你可能会注意到在用户引导显示之前出现短暂的白屏或加载画面。这是由于底层原生视图正在初始化。你可以根据自己的需求和工作流程，选择不同的处理方式。

#### 使用 onFinishedLoading 控制启动页 \{#control-splash-screen-using-onfinishedloading\}

:::note
此方法仅在使用 React 组件时可用，不支持模态展示方式。
:::
推荐在 React Native 中保持启动页或自定义遮罩层可见，直到用户引导完全加载完成，再手动隐藏它。

使用 React 组件（`AdaptyOnboardingView`）时，请等待 `onFinishedLoading` 事件触发后再隐藏启动页或遮罩层：

<Tabs groupId="version" queryString>
<TabItem value="new" label="SDK 版本 3.14 或更高" default>
```typescript showLineNumbers title="React Native (TSX)"

function MyOnboarding({ onboarding }) {
  const [isLoading, setIsLoading] = useState(true);

  const onFinishedLoading = useCallback<OnboardingEventHandlers['onFinishedLoading']>((meta) => {
    // Hide your splash screen or custom overlay here
    setIsLoading(false);
  }, []);

  return (
    <>
      <AdaptyOnboardingView
        onboarding={onboarding}
        onFinishedLoading={onFinishedLoading}
        // ... other callbacks
      />
      {isLoading && <YourCustomLoadingOverlay />}
    </>
  );
}
```

</TabItem>

<TabItem value="old" label="SDK 版本 < 3.14">
```typescript showLineNumbers title="React Native (TSX)"

function MyOnboarding({ onboarding }) {
  const [isLoading, setIsLoading] = useState(true);

  return (
    <>
      <AdaptyOnboardingView
        onboarding={onboarding}
        eventHandlers={{
          onFinishedLoading(meta) {
            // Hide your splash screen or custom overlay here
            setIsLoading(false);
          },
          // ... other handlers
        }}
      />
      {isLoading && <YourCustomLoadingOverlay />}
    </>
  );
}
```

</TabItem>
</Tabs>

#### 自定义原生加载器 \{#customize-native-loader\}

:::important
Expo 托管工作流不支持放置自定义原生布局（例如 Android 上的 `res/layout`）。对于 Expo 应用，控制启动页或使用 React Native 覆盖层是唯一可行的方案。
:::

你可以在 Android 和 iOS 上使用平台特定布局来替换原生加载器。如果你使用的是模态展示方式，这是唯一可行的方案。

不过，这种方式对于 React Native 应用来说通常不太方便：

- 需要分别为 Android 和 iOS 单独实现
- 与 Expo 托管工作流不兼容
为每个平台定义一个占位符：

- **iOS**：将 `AdaptyOnboardingPlaceholderView.xib` 添加到你的 Xcode 项目中。[了解更多](ios-present-onboardings#add-smooth-transitions-between-the-splash-screen-and-onboarding)。
- **Android**：在 `res/layout` 中创建 `adapty_onboarding_placeholder_view.xml`，并在其中定义占位符。[了解更多](android-present-onboardings#add-smooth-transitions-between-the-splash-screen-and-onboarding)。
## 自定义用户引导中链接的打开方式 \{#customize-how-links-open-in-onboardings\}

:::important
自定义用户引导中链接的打开方式需要 Adapty SDK v3.15.1 及以上版本。
:::

默认情况下，用户引导中的链接会在应用内浏览器中打开。这样用户无需切换应用即可查看网页，体验更流畅。

如果你希望改为在外部浏览器中打开链接，可以将 `externalUrlsPresentation` 参数设置为 `WebPresentation.BrowserOutApp` 来自定义此行为：
<Tabs groupId="rn-onboarding-views" queryString>
<TabItem value="component" label="React component" default>
```typescript showLineNumbers title="React Native (TSX)"

function MyOnboarding({ onboarding }) {
  const onAnalytics = useCallback<OnboardingEventHandlers['onAnalytics']>((event, meta) => {}, []);
  const onClose = useCallback<OnboardingEventHandlers['onClose']>((actionId, meta) => {}, []);
  const onCustom = useCallback<OnboardingEventHandlers['onCustom']>((actionId, meta) => {}, []);
  const onPaywall = useCallback<OnboardingEventHandlers['onPaywall']>((actionId, meta) => {}, []);
  const onStateUpdated = useCallback<OnboardingEventHandlers['onStateUpdated']>((action, meta) => {}, []);
  const onFinishedLoading = useCallback<OnboardingEventHandlers['onFinishedLoading']>((meta) => {}, []);
  const onError = useCallback<OnboardingEventHandlers['onError']>((error) => {}, []);

  return (
    <AdaptyOnboardingView
      onboarding={onboarding}
      style={styles.container}
      externalUrlsPresentation={WebPresentation.BrowserOutApp} // default – BrowserInApp
      onAnalytics={onAnalytics}
      onClose={onClose}
      onCustom={onCustom}
      onPaywall={onPaywall}
      onStateUpdated={onStateUpdated}
      onFinishedLoading={onFinishedLoading}
      onError={onError}
    />
  );
}
```
</TabItem>
<TabItem value="modal" label="模态呈现">

```typescript showLineNumbers title="React Native (TSX)"

const view = await createOnboardingView(
  onboarding, 
  { externalUrlsPresentation: WebPresentation.BrowserOutApp } // default – BrowserInApp
);

try {
    await view.present();
} catch (error) {
    // handle the error
}
```
</TabItem>
</Tabs>
## 故障排查 \{#troubleshooting\}

### Android 上系统 UI 遮挡用户引导内容 \{#system-ui-overlaps-onboarding-content-on-android\}

:::note
此设置仅在裸 React Native 项目中受支持。

如果你使用的是 Expo 托管工作流，则无法直接添加此 Android 资源。要应用此设置，必须创建一个自定义 Expo 配置插件，将相应的 Android 资源添加进去，并在 `app.config.js` 中注册。这是必要的，因为 Expo 会替你管理原生 Android 项目。
:::
在 Android 上使用 `AdaptyOnboardingView` 时，状态栏和导航栏等系统 UI 元素可能会覆盖在付费墙内容之上。要解决这个问题，请在应用中添加以下布尔资源：

1. 进入 `android/app/src/main/res/values` 目录。如果没有 `bools.xml` 文件，请创建一个。

2. 添加以下资源：

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

请注意，此更改会对应用中的所有用户引导全局生效。
## 后续步骤 \{#next-steps\}

展示用户引导后，您需要[处理用户交互和事件](react-native-handling-onboarding-events)。了解如何处理用户引导事件，以响应用户操作并跟踪分析数据。