> ## Documentation Index
> Fetch the complete documentation index at: https://documentation.onesignal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Expo SDK 设置

> 使用 Expo SDK 53+ 和 EAS Build 将 OneSignal React Native 和 Expo SDK 集成到您的 iOS、Android 和衍生应用（如 Amazon）的分步指南。

export const SdkReleasesIframe = ({sdkFilter = undefined, viewMode = undefined, height, ...frameProps}) => {
  const baseUrl = 'https://onesignal.github.io/sdk-releases';
  const buildUrl = (theme, sdkFilter, viewMode) => {
    const url = new URL(baseUrl);
    const params = new URLSearchParams();
    if (theme) {
      params.set('theme', theme);
    }
    if (sdkFilter) {
      params.set('sdk', sdkFilter);
    }
    if (viewMode) {
      params.set('viewMode', viewMode);
    }
    if (params.toString()) {
      url.search = params.toString();
    }
    return url.toString();
  };
  const detectTheme = () => {
    if (document.documentElement.classList.contains('dark')) {
      return 'dark';
    }
    return 'light';
  };
  const [theme, setTheme] = useState('light');
  const [iframeSrc, setIframeSrc] = useState(() => {
    const initialTheme = detectTheme();
    return buildUrl(initialTheme, sdkFilter, viewMode);
  });
  useEffect(() => {
    const currentTheme = detectTheme();
    setTheme(currentTheme);
    setIframeSrc(buildUrl(currentTheme, sdkFilter, viewMode));
    const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
    const handleThemeChange = () => {
      const newTheme = detectTheme();
      setTheme(newTheme);
      setIframeSrc(buildUrl(newTheme, sdkFilter, viewMode));
    };
    if (mediaQuery.addEventListener) {
      mediaQuery.addEventListener('change', handleThemeChange);
    } else {
      mediaQuery.addListener(handleThemeChange);
    }
    window.addEventListener('storage', handleThemeChange);
    const observer = new MutationObserver(handleThemeChange);
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ['class', 'data-theme']
    });
    return () => {
      if (mediaQuery.removeEventListener) {
        mediaQuery.removeEventListener('change', handleThemeChange);
      } else {
        mediaQuery.removeListener(handleThemeChange);
      }
      window.removeEventListener('storage', handleThemeChange);
      observer.disconnect();
    };
  }, [sdkFilter, viewMode]);
  const getIframeHeight = () => {
    if (viewMode === 'table') {
      return '450';
    }
    if (viewMode === 'mini') {
      return '170';
    }
    return '800';
  };
  const iframeHeight = height || getIframeHeight();
  return <Frame {...frameProps}>
      <iframe src={iframeSrc} width="100%" height={iframeHeight} frameBorder="0" style={{
    border: "none"
  }} title="SDK Releases" key={iframeSrc} />
    </Frame>;
};

<SdkReleasesIframe sdkFilter="reactnative" viewMode="mini" />

## 概述

## 要求

* 一个托管的 Expo 应用。对于原生 React Native 应用，请参阅 [React Native SDK setup](./react-native-sdk-setup)。

* Expo SDK 53+（React Native 0.79+），需启用[新架构](https://reactnative.dev/docs/new-architecture-intro)

* EAS CLI（[EAS Build 文档](https://docs.expo.dev/build/introduction/)）

* 已配置的 OneSignal 应用和平台

**iOS 要求**

* 带有 Xcode 14+ 的 macOS（设置说明使用 Xcode 16.2）
* iOS 12+、iPadOS 12+ 设备或运行 iOS 16.2+ 的 Xcode 模拟器
* CocoaPods 1.16.2+

**Android 要求**

* 安装了 Google Play 商店（服务）的 Android 7.0+ 设备或模拟器

### 配置您的 OneSignal 应用和平台

使用您支持的平台配置您的 OneSignal 应用——Apple (APNs)、Google (FCM)、华为 (HMS) 和/或 Amazon (ADM)。

<Note>
  如果您的组织已有 OneSignal 账户，请[申请加入](/docs/cn/manage-team-members)组织。否则，请[注册免费账户](https://onesignal.com)以开始使用。
</Note>

<Accordion title="分步设置说明" icon="circle-chevron-down">
  <Steps>
    <Step title="创建或选择您的应用">
      点击 **新应用/网站** 创建新应用，或在 **设置 > 推送和应用内** 中向现有应用添加平台。选择您要配置的平台，然后点击 **下一步：配置您的平台**。

      <Frame caption="设置您的第一个 OneSignal 应用、组织和频道。">
        <img src="https://mintcdn.com/onesignal/BK2J-grzBpDdh8NC/images/dashboard/new-app-org-channel.png?fit=max&auto=format&n=BK2J-grzBpDdh8NC&q=85&s=ee0045484152ed15095f619344aa0564" alt="OneSignal 控制台显示包含组织名称、应用名称和频道选择的新应用设置流程" width="2592" height="1904" data-path="images/dashboard/new-app-org-channel.png" />
      </Frame>
    </Step>

    <Step title="配置平台凭据">
      为您的平台输入凭据：

      * **Android**：[设置 Firebase 凭据](/docs/cn/android-firebase-credentials)
      * **iOS**：[p8 令牌（推荐）](/docs/cn/ios-p8-token-based-connection-to-apns) 或 [p12 证书](/docs/cn/ios-p12-generate-certificates)
      * **Amazon**：[生成 API 密钥](/docs/cn/generate-an-amazon-api-key)
      * **华为**：[授权 OneSignal](/docs/cn/authorize-onesignal-to-send-huawei-push)

      输入您的凭据后点击 **保存并继续**。
    </Step>

    <Step title="保存您的应用 ID 并安装 SDK">
      您的 **应用 ID** 显示在最终屏幕上。复制并保存它——初始化 SDK 时需要使用它。选择您的 SDK 平台，然后按照设置指南操作。

      <Frame caption="保存您的应用 ID 并邀请其他团队成员。">
        <img src="https://mintcdn.com/onesignal/VypVshrFHTBZfEma/images/dashboard/app-id-and-team-invite.png?fit=max&auto=format&n=VypVshrFHTBZfEma&q=85&s=e1e2aab6cca7c4aa6b9a76eff362d5af" alt="OneSignal 控制台显示设置完成后的应用 ID 和团队邀请选项" width="2592" height="1904" data-path="images/dashboard/app-id-and-team-invite.png" />
      </Frame>
    </Step>
  </Steps>
</Accordion>

***

## SDK 设置

### 1. 添加 SDK

使用 Expo CLI 安装 OneSignal Expo 插件。

```shell npm theme={null}
npx expo install onesignal-expo-plugin
```

将 `react-native-onesignal` 包添加到您的项目中。

<CodeGroup>
  ```shell npm theme={null}
    npm install --save react-native-onesignal
  ```

  ```shell Yarn theme={null}
  yarn add react-native-onesignal
  ```
</CodeGroup>

### 2. 配置插件

打开您的 `app.json`（或 `app.config.js` / `app.config.ts`）。在 `plugins` 数组中，您应该看到 `"onesignal-expo-plugin"`。配置所需的插件属性：

<Tabs>
  <Tab title="app.config.ts">
    从 `onesignal-expo-plugin` 2.6.0 开始，您可以导入 `withOneSignal`，以获得完整的 TypeScript 支持以及插件属性的自动补全。

    ```ts app.config.ts theme={null}
    import { ConfigContext, ExpoConfig } from '@expo/config';
    import withOneSignal from 'onesignal-expo-plugin/plugin';

    export default ({ config }: ConfigContext): ExpoConfig => ({
      ...config,
      ios: {
        bundleIdentifier: 'com.yourcompany.yourapp',
        infoPlist: {
          UIBackgroundModes: ['remote-notification'],
        },
        entitlements: {
          'aps-environment': 'development',
        },
      },
      android: {
        package: 'com.yourcompany.yourapp',
      },
      plugins: [
        withOneSignal({
          mode: 'development',
        }),
      ],
    });
    ```
  </Tab>

  <Tab title="app.json">
    ```json app.json theme={null}
      {
        "expo": {
          "ios": {
            "bundleIdentifier": "com.yourcompany.yourapp", // ✅ Required for iOS builds
            "infoPlist": {
              "UIBackgroundModes": ["remote-notification"] // ✅ 推送通知所需
            },
            "entitlements": {
              "aps-environment": "development" // ✅ 推送通知所需，对于 Testflight 和 App Store 构建改为 "production"
            }
          },
          "android": {
            "package": "com.yourcompany.yourapp" // ✅ Required for Android builds
          },
          "plugins": [
            [
              "onesignal-expo-plugin",
              {
                "mode": "development"
              }
            ]
          ]
        }
      }
    ```
  </Tab>
</Tabs>

<Warning>
  确保将插件 `[onesignal-expo-plugin]` 添加到插件数组的前面。它应该是数组中的第一个插件。这将防止 `OneSignal/OneSignal.h file not found` 错误。
</Warning>

<Accordion title="额外的插件属性。">
  |            属性            |  必填 | 说明                                                                                                                                                                                                              |
  | :----------------------: | :-: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  |          `mode`          |  ✅  | 配置 [APNs 环境](https://developer.apple.com/documentation/bundleresources/entitlements/aps-environment) 权利。使用 `"development"` 或 `"production"` — 测试时使用 `"development"`，TestFlight 和 App Store 构建使用 `"production"`。 |
  |         `devTeam`        | 已弃用 | **已弃用。** 建议在 Expo 配置中使用 [`ios.appleTeamId`](https://docs.expo.dev/versions/latest/config/app/#appleteamid)。若未设置 `appleTeamId`，插件会回退使用 `devTeam`（例如 `"91SW8A37CR"`）。                                             |
  | `iPhoneDeploymentTarget` |  ❌  | 添加 iOS [通知服务扩展](./service-extensions) 时使用的 `IPHONEOS_DEPLOYMENT_TARGET`。应与 Podfile 中的最低 iOS 版本一致（例如 `"15.0"`）。                                                                                                  |
  |       `smallIcons`       |  ❌  | 指向 Android [小通知图标](./notification-icons#小通知图标) 的本地路径数组（白色、透明、96×96px）。图像会自动缩放并放入对应资源目录。示例：`["./assets/ic_stat_onesignal_default.png"]`                                                                          |
  |       `largeIcons`       |  ❌  | 指向 Android [大通知图标](./notification-icons#大通知图标) 的本地路径数组（白色、透明、256×256px）。示例：`["./assets/ic_onesignal_large_icon_default.png"]`                                                                                   |
  |  `smallIconAccentColor`  |  ❌  | Android 通知图标强调色的十六进制颜色值（例如 `"#FF0000"`）。                                                                                                                                                                        |
  |     `iosNSEFilePath`     |  ❌  | Objective-C 自定义通知服务扩展的本地路径。示例：`"./assets/NotificationService.m"`                                                                                                                                                |
  |      `appGroupName`      |  ❌  | 自定义 iOS [应用组](./ios-sdk-setup#3-将应用目标添加到应用组) 名称。若省略，默认为 `"group.{ios.bundleIdentifier}.onesignal"`（例如 `"group.com.example.myapp.onesignal2"`）。                                                                  |
  |   `nseBundleIdentifier`  |  ❌  | NSE 包标识符的后缀。完整标识符为 `{ios.bundleIdentifier}.{nseBundleIdentifier}`。若省略，默认为 `OneSignalNotificationServiceExtension`。                                                                                              |
  |       `disableNSE`       |  ❌  | 若为 `true`，则不添加 iOS NSE。徽章、确认送达、媒体附件和操作按钮需要 NSE — 仅在仅需基础推送时禁用。                                                                                                                                                   |
  |     `disableLocation`    |  ❌  | 若为 `true`，则从 iOS 和 Android 构建中排除原生 OneSignal 位置模块。仅当您的应用不调用 `OneSignal.Location` 时使用。                                                                                                                           |
  |         `sounds`         |  ❌  | 自定义通知声音的本地路径数组（仅 `.wav`，≤30 秒）。会复制到 iOS 应用包和 Android 的 `res/raw/`。示例：`["./assets/notification_sound.wav"]`。参阅 [通知声音](./notification-sounds)。                                                                    |
</Accordion>

#### 可选：禁用位置模块

如果您的应用不使用 `OneSignal.Location`，请在 OneSignal Expo 插件 props 中将 `disableLocation` 设置为 `true`。此选项需要 `react-native-onesignal` 5.5.1 或更高版本。该插件会配置原生依赖项解析，使 `react-native-onesignal` 排除位置模块。在 iOS 上，插件会写入 CocoaPods 解析期间使用的 Podfile 环境设置。在 Android 上，插件会将 `onesignal.disableLocation=true` 写入生成的 Gradle properties。

<CodeGroup>
  ```ts app.config.ts theme={null}
  plugins: [
    withOneSignal({
      mode: 'development',
      disableLocation: true,
    }),
  ],
  ```

  ```json app.json theme={null}
  "plugins": [
    [
      "onesignal-expo-plugin",
      {
        "mode": "development",
        "disableLocation": true
      }
    ]
  ]
  ```
</CodeGroup>

### 3. Initialize SDK

根据您的 Expo 结构（传统应用入口或 Expo Router），按照这些选项初始化 OneSignal。

<Tabs>
  <Tab title="传统应用入口">
    在您的 `App.tsx` 或 `App.js` 文件中使用提供的方法初始化 OneSignal。

    Replace `YOUR_APP_ID` with your OneSignal App ID found in your OneSignal dashboard **Settings > [Keys & IDs](./keys-and-ids)**.

    <Note>
      If you don't have access to the OneSignal app, ask your [Team Members](./manage-team-members) to invite you.
    </Note>

    ```javascript App.tsx theme={null}
    import React, { useEffect } from 'react';
    // 引入 OneSignal 包
    import { OneSignal, LogLevel } from 'react-native-onesignal';

    export default function App() {
      useEffect(() => {
        // 启用详细日志记录用于调试（在生产环境中移除）
        OneSignal.Debug.setLogLevel(LogLevel.Verbose);

        // 替换为您的 OneSignal App ID（位于 Dashboard > Settings > Keys & IDs）
        OneSignal.initialize('YOUR_APP_ID');

        // 首次启动时提示推送权限。
        // 在生产环境中，建议改用应用内消息以获得更好的订阅率。
        OneSignal.Notifications.requestPermission(false);

        // 一次性定义监听器，确保添加和移除时使用相同的引用。
        const clickListener = (event) => {
          console.log('OneSignal: notification clicked:', event);
        };

        // 在 v5 中，前台通知会自动显示。
        // 调用 event.preventDefault() 进行抑制，然后在异步处理完成后
        // 调用 event.getNotification().display() 进行显示。
        const foregroundListener = (event) => {
          console.log('OneSignal: foreground will display:', event);
        };

        OneSignal.Notifications.addEventListener('click', clickListener);
        OneSignal.Notifications.addEventListener('foregroundWillDisplay', foregroundListener);

        // 组件卸载时清理监听器，避免内存泄漏。
        // 必须传入与 addEventListener 相同的监听器引用。
        return () => {
          OneSignal.Notifications.removeEventListener('click', clickListener);
          OneSignal.Notifications.removeEventListener('foregroundWillDisplay', foregroundListener);
        };
      }, []);
    }
    ```
  </Tab>

  <Tab title="Expo 路由器">
    在您的 `app/_layout.tsx` 或 `app/_layout.js` 文件中使用提供的方法初始化 OneSignal。

    Replace `YOUR_APP_ID` with your OneSignal App ID found in your OneSignal dashboard **Settings > [Keys & IDs](./keys-and-ids)**.

    <Note>
      If you don't have access to the OneSignal app, ask your [Team Members](./manage-team-members) to invite you.
    </Note>

    下面的示例使用 `App` 作为函数名 — Expo Router 接受任意默认导出的组件，所以将其重命名为 `RootLayout` 是可选但更符合惯例的做法。

    ```javascript App.tsx theme={null}
    import React, { useEffect } from 'react';
    // 引入 OneSignal 包
    import { OneSignal, LogLevel } from 'react-native-onesignal';

    export default function App() {
      useEffect(() => {
        // 启用详细日志记录用于调试（在生产环境中移除）
        OneSignal.Debug.setLogLevel(LogLevel.Verbose);

        // 替换为您的 OneSignal App ID（位于 Dashboard > Settings > Keys & IDs）
        OneSignal.initialize('YOUR_APP_ID');

        // 首次启动时提示推送权限。
        // 在生产环境中，建议改用应用内消息以获得更好的订阅率。
        OneSignal.Notifications.requestPermission(false);

        // 一次性定义监听器，确保添加和移除时使用相同的引用。
        const clickListener = (event) => {
          console.log('OneSignal: notification clicked:', event);
        };

        // 在 v5 中，前台通知会自动显示。
        // 调用 event.preventDefault() 进行抑制，然后在异步处理完成后
        // 调用 event.getNotification().display() 进行显示。
        const foregroundListener = (event) => {
          console.log('OneSignal: foreground will display:', event);
        };

        OneSignal.Notifications.addEventListener('click', clickListener);
        OneSignal.Notifications.addEventListener('foregroundWillDisplay', foregroundListener);

        // 组件卸载时清理监听器，避免内存泄漏。
        // 必须传入与 addEventListener 相同的监听器引用。
        return () => {
          OneSignal.Notifications.removeEventListener('click', clickListener);
          OneSignal.Notifications.removeEventListener('foregroundWillDisplay', foregroundListener);
        };
      }, []);
    }
    ```
  </Tab>
</Tabs>

**使用 `useCallback` 复用监听器**

如果您的监听器需要访问 props 或 state，请在 `useEffect` 外部使用 `useCallback` 定义它，确保添加和移除时使用相同的引用。若传给 `addEventListener` 和 `removeEventListener` 的函数引用不同，则不会有任何效果 — 监听器不会被移除，并可能在组件卸载后继续触发。

```javascript theme={null}
import React, { useCallback, useEffect } from 'react';
import { OneSignal } from 'react-native-onesignal';

export default function App() {
  const clickListener = useCallback((event) => {
    console.log('OneSignal: notification clicked:', event);
    // 依赖项可根据需要调整
  }, []);

  useEffect(() => {
    OneSignal.Notifications.addEventListener('click', clickListener);
    return () => {
      OneSignal.Notifications.removeEventListener('click', clickListener);
    };
  }, [clickListener]);
}
```

<Check>
  查看我们的 [OneSignal Expo Plugin GitHub 仓库](https://github.com/OneSignal/onesignal-expo-plugin) 以获取更多配置选项、更复杂的设置说明或提出问题。我们的 SDK 是开源的，欢迎提交 PR！
</Check>

***

## Android 设置

确保您的 OneSignal 应用已使用您的 [Firebase 凭据](/docs/cn/android-firebase-credentials) 为 Android 平台进行配置。

设置您的[通知图标](/docs/cn/notification-icons)以匹配您的应用品牌。如果跳过此步骤，推送通知将显示默认的铃铛图标。

**为 Android 构建**

此时，您应该能够在物理 Android 设备或模拟器上无问题地构建和运行您的应用。

<Check>
  确认您的 Android 构建正常工作后：

  * 如果适用，继续进行 [iOS 设置](#ios-setup)。
  * 或者跳转到[测试 OneSignal SDK 集成](#testing-the-onesignal-sdk-integration)。
</Check>

***

## iOS setup

确保您的 OneSignal 应用已配置为使用 [p8 令牌（推荐）](./ios-p8-token-based-connection-to-apns) 或 [p12 证书](./ios-p12-generate-certificates) 的 iOS 平台。

<Warning>
  这应该使用您的 EAS 配置中相同的凭据设置。
</Warning>

### iOS 构建

您现在应该能够在真实的 iOS 设备或 iOS 模拟器（16.2+）上构建并运行您的应用。

#### Common iOS build errors

<Accordion title="循环内部...构建可能产生不可靠结果。">
  在使用 Xcode 15+ 构建时您可能会看到此错误，这是由于影响跨平台系统的默认配置更改。

  1. 在 Xcode 中打开您的 `.xcworkspace` 文件夹，并导航到 **您的应用目标 > Build Phases**。
  2. 您应该有一个名为 **"Embed Foundation Extensions"** 或 **"Embed App Extensions"** 的阶段。
  3. 拖动并移动此构建阶段到 **"Run Script"** 之\_上\_。
  4. 构建并运行您的应用。错误应该得到解决。

  <Frame caption="Xcode 中 Build Phases 的正确顺序。">
    <img src="https://mintcdn.com/onesignal/_KaXe4GQkxsEfa17/images/docs/347d494eab3ea84c977d5785d16c1602d25204c9333b1ec1166c520d004a87d6-Screenshot_2025-03-06_at_4.23.01_PM.png?fit=max&auto=format&n=_KaXe4GQkxsEfa17&q=85&s=279facba4338900c1d123934bf2eb2e6" width="2708" height="1486" data-path="images/docs/347d494eab3ea84c977d5785d16c1602d25204c9333b1ec1166c520d004a87d6-Screenshot_2025-03-06_at_4.23.01_PM.png" />
  </Frame>

  <Frame caption="取消勾选 仅在安装时复制。">
    <img src="https://mintcdn.com/onesignal/KSCNwSpBCNSQ8xdF/images/docs/f7ef57730ef4aba1d669c8c6efac6be2a18c3035564c658967e7cf2e50708933-Screenshot_2025-03-06_at_4.29.29_PM.png?fit=max&auto=format&n=KSCNwSpBCNSQ8xdF&q=85&s=7175d9f2c5819343c58b60045e40358d" width="2620" height="1398" data-path="images/docs/f7ef57730ef4aba1d669c8c6efac6be2a18c3035564c658967e7cf2e50708933-Screenshot_2025-03-06_at_4.29.29_PM.png" />
  </Frame>
</Accordion>

<Accordion title="PBXGroup 错误">
  <Info>
    RuntimeError - `PBXGroup` attempted to initialize an object with unknown ISA `PBXFileSystemSynchronizedRootGroup` from attributes: `{"isa"=>"...", "exceptions"=>["//", "..."], "explicitFileTypes"=>{}, "explicitFolders"=>[], "path"=>"OneSignalNotificationServiceExtension", "sourceTree"=>"<group>"}`
  </Info>

  Fix:

  1. 找到错误中 "path" 下列出的文件夹
  2. In Xcode project sidebar, right-click the folder
  3. Select **Convert to Group**

  <Frame caption="PBXGroup 的路径错误。">
    <img src="https://mintcdn.com/onesignal/tc0EvmtSSX56SX0c/images/docs/92100ba09cde1f8de53dae773dca16847c7e1c6329bc9f4172331f2bc2191592-16c6fb188242f0e43237a0da47c6a2a9.png?fit=max&auto=format&n=tc0EvmtSSX56SX0c&q=85&s=6fea922df9bca81d0ca5d3d7b346f07a" width="659" height="216" data-path="images/docs/92100ba09cde1f8de53dae773dca16847c7e1c6329bc9f4172331f2bc2191592-16c6fb188242f0e43237a0da47c6a2a9.png" />
  </Frame>

  <br />

  <Frame caption="将文件夹转换为组。">
    <img src="https://mintcdn.com/onesignal/56ctKxZSV4m5VEkn/images/docs/b90d34ba26c94f437fd553514647fc4024ec42301ad2798eba7faec695974720-d46625820efed3f9dbca1e223ac0797f.png?fit=max&auto=format&n=56ctKxZSV4m5VEkn&q=85&s=5034133ed9e06897abe672a62ff94913" width="483" height="364" data-path="images/docs/b90d34ba26c94f437fd553514647fc4024ec42301ad2798eba7faec695974720-d46625820efed3f9dbca1e223ac0797f.png" />
  </Frame>
</Accordion>

<Check>
  确认您的 iOS 构建工作正常后，继续进行 [测试 OneSignal SDK 集成](#testing-the-onesignal-sdk-integration)。
</Check>

***

## 测试 OneSignal SDK 集成

本指南帮助您通过测试推送通知、订阅注册和应用内消息来验证 OneSignal SDK 集成是否正常工作。

### 检查移动端订阅

<Steps>
  <Step title="在测试设备上启动您的应用。">
    如果您在初始化时添加了 `requestPermission` 方法，原生推送权限提示应该会自动出现。

    <Frame caption="iOS 和 Android 推送权限提示">
      <img src="https://mintcdn.com/onesignal/RWtLFPeffHrC81wI/images/docs/a90c2cc443f5fe9e7c80368c680a16cf1ca6203f7b28a0a6eec212add8510f80-Untitled_design_11.png?fit=max&auto=format&n=RWtLFPeffHrC81wI&q=85&s=96dbf224b3ae93b3d814712cdc5416ba" width="1920" height="1080" data-path="images/docs/a90c2cc443f5fe9e7c80368c680a16cf1ca6203f7b28a0a6eec212add8510f80-Untitled_design_11.png" />
    </Frame>
  </Step>

  <Step title="检查您的 OneSignal 控制台">
    在接受提示之前，请检查 OneSignal 控制台：

    * 转到 **受众 > 订阅**。
    * 您应该看到一个状态为"从未订阅"的新条目。

    <Frame caption="控制台显示 '从未订阅' 状态的订阅">
      <img src="https://mintcdn.com/onesignal/Xl2NHJvxakrK4JbL/images/docs/f19fa5ada3572ce14447bb5639744e9da75cd7a3ab43ecc1a057f2ed92b38e6f-Screenshot_2025-03-16_at_14.55.39.png?fit=max&auto=format&n=Xl2NHJvxakrK4JbL&q=85&s=b04ca3217e22155841b500a55c7f1511" width="1588" height="976" data-path="images/docs/f19fa5ada3572ce14447bb5639744e9da75cd7a3ab43ecc1a057f2ed92b38e6f-Screenshot_2025-03-16_at_14.55.39.png" />
    </Frame>
  </Step>

  <Step title="返回应用并在提示中点击允许。" />

  <Step title="刷新 OneSignal 控制台的订阅页面。">
    订阅状态现在应该显示为**已订阅**。

    <Frame caption="控制台显示 '已订阅' 状态的订阅">
      <img src="https://mintcdn.com/onesignal/0qspEXXeJ8zJbkJ-/images/docs/85b0376cdcc6f93fb7b3895b18cd1788d2342776d7995909881e5c64dd40fb62-Screenshot_2025-03-16_at_15.57.34.png?fit=max&auto=format&n=0qspEXXeJ8zJbkJ-&q=85&s=c6abec64d102b84e30f6c9c0327808ef" width="1588" height="976" data-path="images/docs/85b0376cdcc6f93fb7b3895b18cd1788d2342776d7995909881e5c64dd40fb62-Screenshot_2025-03-16_at_15.57.34.png" />
    </Frame>

    <Check>您已成功创建了[移动端订阅](/docs/cn/subscriptions)。
    移动端订阅是在用户首次在设备上打开您的应用时创建的，或者在同一设备上卸载并重新安装您的应用时创建的。</Check>
  </Step>
</Steps>

### 设置测试订阅

测试订阅有助于在发送消息之前测试推送通知。

<Steps>
  <Step title="添加到测试订阅。">
    在控制台中，在订阅旁边，点击**选项（三个点）**按钮并选择**添加到测试订阅**。

    <Frame caption="将设备添加到测试订阅">
      <img src="https://mintcdn.com/onesignal/NCUI56Tiw7V-s0dT/images/dashboard/add-to-test-subscriptions.png?fit=max&auto=format&n=NCUI56Tiw7V-s0dT&q=85&s=2455d4cd74ea4ad686f76730cd95bbaa" width="1188" height="742" data-path="images/dashboard/add-to-test-subscriptions.png" />
    </Frame>
  </Step>

  <Step title="为您的订阅命名。">
    为订阅命名，以便您稍后能够在**测试订阅标签**中轻松识别您的设备。
  </Step>

  <Step title="创建测试用户分组。">
    转到 **受众 > 分组 > 新建分组**。
  </Step>

  <Step title="为分组命名。">
    将分组命名为 `Test Users`（名称很重要，因为稍后会使用到）。
  </Step>

  <Step title="添加测试用户过滤器并点击创建分组。">
    <Frame caption="使用测试用户过滤器创建 'Test Users' 分组">
      <img src="https://mintcdn.com/onesignal/NCUI56Tiw7V-s0dT/images/dashboard/create-test-users-segment.png?fit=max&auto=format&n=NCUI56Tiw7V-s0dT&q=85&s=91b8a021be6e83662854e68ec3e1da04" width="1188" height="742" data-path="images/dashboard/create-test-users-segment.png" />
    </Frame>

    <Check>您已成功创建了测试用户分组。
    现在我们可以测试向这个单独的设备和测试用户组发送消息。</Check>
  </Step>
</Steps>

### 通过 API 发送测试推送

<Steps>
  <Step title="获取您的应用 API 密钥和应用 ID。">
    在您的 OneSignal 控制台中，转到 **设置 > [密钥和 ID](/docs/cn/keys-and-ids)**。
  </Step>

  <Step title="更新提供的代码。">
    将下面代码中的 `YOUR_APP_API_KEY` 和 `YOUR_APP_ID` 替换为您的实际密钥。此代码使用我们之前创建的 `Test Users` 分组。

    ```curl theme={null}
    curl -X \
    POST --url 'https://api.onesignal.com/notifications' \
     --header 'content-type: application/json; charset=utf-8' \
     --header 'authorization: Key YOUR_APP_API_KEY' \
     --data \
     '{
      "app_id": "YOUR_APP_ID",
      "target_channel": "push",
      "name": "Testing basic setup",
      "headings": {
      	"en": "👋"
      },
      "contents": {
        "en": "Hello world!"
      },
      "included_segments": [
        "Test Users"
      ],
      "ios_attachments": {
        "onesignal_logo": "https://avatars.githubusercontent.com/u/11823027?s=200&v=4"
      },
      "big_picture": "https://avatars.githubusercontent.com/u/11823027?s=200&v=4"
    }'
    ```
  </Step>

  <Step title="运行代码。">
    在您的终端中运行代码。
  </Step>

  <Step title="检查图片和确认送达。">
    如果所有设置步骤都成功完成，测试订阅应该会收到包含图片的通知：

    <Frame caption="iOS 和 Android 上包含图片的推送通知">
      <img src="https://mintcdn.com/onesignal/Z6xkXGfmy814If53/images/docs/e4e3e812eb6841ff11795a6ee0ea36eff483920ea9266733d6948ed34df3def3-Untitled_design_9.png?fit=max&auto=format&n=Z6xkXGfmy814If53&q=85&s=9bf6f4a73e38ec424b8cfec75a474a26" width="1200" height="800" data-path="images/docs/e4e3e812eb6841ff11795a6ee0ea36eff483920ea9266733d6948ed34df3def3-Untitled_design_9.png" />
    </Frame>

    <Info>图片在折叠的通知视图中会显得很小。展开通知以查看完整图片。</Info>
  </Step>

  <Step title="检查确认送达。">
    在您的控制台中，转到 **送达 > 已发送消息**，然后点击消息查看统计数据。

    您应该会看到**已确认**统计，表示设备收到了推送。
    <Check>您已成功通过我们的 API 向分组发送了通知。</Check>

    <Warning>
      * 没有收到图片？您的[通知服务扩展](#ios-setup)可能缺失。
      * 没有确认送达？请检查您的[应用组设置](#ios-setup)。
      * 遇到问题？将 API 请求和应用启动从开始到结束的日志复制粘贴到 `.txt` 文件中。然后将两者都发送给 `support@onesignal.com`。
    </Warning>
  </Step>
</Steps>

### 发送应用内消息

[应用内消息](/docs/cn/in-app-messages-setup)让您可以在用户使用您的应用时与他们进行沟通。

<Steps>
  <Step title="在设备上关闭或将您的应用切换到后台。">
    这是因为用户必须在新会话开始\_之前\_满足应用内受众条件。在 OneSignal 中，当用户在应用处于后台或关闭至少 30 秒后重新打开应用时，会开始一个新会话。更多详情，请参阅我们的[应用内消息如何显示](/docs/cn/in-app-messages-setup#how-are-iams-displayed%3F)指南。
  </Step>

  <Step title="创建应用内消息。">
    * 在您的 OneSignal 控制台中，导航到 **消息 > 应用内 > 新建应用内消息**。
    * 找到并选择**欢迎**消息。
    * 将您的受众设置为我们之前使用的 **Test Users** 分组。

    <Frame caption="使用应用内消息定位 'Test Users' 分组">
      <img src="https://mintcdn.com/onesignal/3zq1PvSaqvUE2bIx/images/docs/2979dfb2c6e0711669ebe737d78d975dcfed9f8117bdd68846255b9fc91e4771-Screenshot_2025-03-17_at_14.56.23.png?fit=max&auto=format&n=3zq1PvSaqvUE2bIx&q=85&s=f705ee679a9248dab378305e15fa24bf" width="1410" height="752" data-path="images/docs/2979dfb2c6e0711669ebe737d78d975dcfed9f8117bdd68846255b9fc91e4771-Screenshot_2025-03-17_at_14.56.23.png" />
    </Frame>
  </Step>

  <Step title="如需要，请自定义消息内容。">
    <Frame caption="应用内欢迎消息的自定义示例">
      <img src="https://mintcdn.com/onesignal/YOTSrtBSoqdrJ37A/images/docs/4c511ebdb04f33055556b9969bab8deee0d62154573cf0b41ffb25cc8431e7c0-Screenshot_2025-03-17_at_14.59.37.png?fit=max&auto=format&n=YOTSrtBSoqdrJ37A&q=85&s=6134cc70e578d1055f770edcbad47efb" width="1646" height="1070" data-path="images/docs/4c511ebdb04f33055556b9969bab8deee0d62154573cf0b41ffb25cc8431e7c0-Screenshot_2025-03-17_at_14.59.37.png" />
    </Frame>
  </Step>

  <Step title="将触发器设置为 '应用打开时'。" />

  <Step title="安排频率。">
    在 **安排 > 您希望多久显示一次此消息？** 下选择 **每次触发条件满足时**。

    <Frame caption="应用内消息安排选项">
      <img src="https://mintcdn.com/onesignal/9_Q1FZLh6C0BFLq-/images/docs/c48ccaf33a74d5aa442c768a18b8e642024b89305aae665d613aee1d8bde43ec-Screenshot_2025-03-17_at_15.00.40.png?fit=max&auto=format&n=9_Q1FZLh6C0BFLq-&q=85&s=9a57431acffa267d22af4e19052fb5ee" width="1646" height="1070" data-path="images/docs/c48ccaf33a74d5aa442c768a18b8e642024b89305aae665d613aee1d8bde43ec-Screenshot_2025-03-17_at_15.00.40.png" />
    </Frame>
  </Step>

  <Step title="使消息生效。">
    点击 **使消息生效**，这样每次测试用户打开应用时都可以使用该消息。
  </Step>

  <Step title="打开应用并查看消息。">
    应用内消息生效后，打开您的应用。您应该会看到它显示：

    <Frame caption="在设备上显示的欢迎应用内消息">
      <img src="https://mintcdn.com/onesignal/RWtLFPeffHrC81wI/images/docs/a7ed4bb02be56900a65d2519e3d69f9c9b2c2a1c65fe740f07789e4ffe79cd67-Untitled_design_10.png?fit=max&auto=format&n=RWtLFPeffHrC81wI&q=85&s=6f692b569706ca39df0b4cc2b70f3de2" width="1920" height="1080" data-path="images/docs/a7ed4bb02be56900a65d2519e3d69f9c9b2c2a1c65fe740f07789e4ffe79cd67-Untitled_design_10.png" />
    </Frame>

    <Warning>
      没有看到消息？

      * 开始新会话
        * 您必须关闭或将应用切换到后台至少 30 秒后再重新打开。这可以确保开始新会话。
        * 更多信息，请参阅[应用内消息如何显示](/docs/cn/in-app-messages-setup#how-are-iams-displayed%3F)。
      * 仍在 `Test Users` 分组中？
        * 如果您重新安装或更换了设备，请重新将设备添加到[测试订阅](#set-up-test-subscriptions)并确认它是 Test Users 分组的一部分。
      * 遇到问题？
        * 在重现上述步骤时，请遵循[获取调试日志](/docs/cn/capturing-a-debug-log)。这将生成额外的日志，您可以与 `support@onesignal.com` 分享，我们将帮助调查正在发生的情况。
    </Warning>
  </Step>
</Steps>

<Check>
  您已成功设置 OneSignal SDK 并学习了重要概念，如：

  * 收集[订阅](/docs/cn/subscriptions)，设置[测试订阅](/docs/cn/find-set-test-subscriptions)，以及创建[分组](/docs/cn/segmentation)。
  * 使用分组和我们的[创建消息](/reference/create-message) API 发送带图片的[推送](/docs/cn/push)和[确认送达](/docs/cn/confirmed-delivery)。
  * 发送[应用内消息](/docs/cn/in-app-messages-setup)。

  继续阅读本指南以在您的应用中识别用户并设置其他功能。
</Check>

***

## 用户识别

之前，我们演示了如何创建移动端[订阅](/docs/cn/subscriptions)。现在我们将扩展到使用 OneSignal SDK 在所有订阅（包括推送、电子邮件和短信）中识别[用户](/docs/cn/users)。我们将涵盖外部 ID、标签、多渠道订阅、隐私和事件跟踪，以帮助您统一用户并跨平台与他们互动。

### 分配外部 ID

使用外部 ID 通过您后端的用户标识符在设备、电子邮件地址和电话号码之间一致地识别用户。这确保您的消息传递在各个渠道和第三方系统中保持统一（对[集成](/docs/cn/integrations)特别重要）。

每次您的应用识别用户时，使用我们 SDK 的[`login` 方法](/docs/cn/mobile-sdk-reference#login-external-id)设置外部 ID。

<Note>
  OneSignal 为订阅（订阅 ID）和用户（OneSignal ID）生成唯一的只读 ID。

  当用户在不同设备上下载您的应用、订阅您的网站，和/或在您的应用之外提供电子邮件地址和电话号码时，将创建新的订阅。

  强烈建议通过我们的 SDK 设置外部 ID，以在用户的所有订阅中识别用户，无论订阅是如何创建的。
</Note>

### 添加数据标签

[标签](/docs/cn/add-user-data-tags)是字符串数据的键值对，您可以使用它们来存储用户属性（如 `username`、`role` 或偏好）和事件（如 `purchase_date`、`game_level` 或用户交互）。标签支持高级[消息个性化](/docs/cn/message-personalization)和[分组](/docs/cn/segmentation)，允许更高级的用例。

在您的应用中发生事件时，使用我们 SDK 的[`addTag` 和 `addTags` 方法](/docs/cn/mobile-sdk-reference#data-tags)设置标签。

在这个示例中，用户达到了第 6 级，可以通过名为 `current_level` 的标签识别，其值设置为 `6`。

<Frame caption="OneSignal 中带有名为'current_level'标签设置为'6'的用户档案">
  <img src="https://mintcdn.com/onesignal/4HyuQPBpu-4xjmQC/images/docs/d4674261847231079fecc176ba88065409c90943e3854b9df200457325a0aed4-Screenshot_2025-03-18_at_14.47.25.png?fit=max&auto=format&n=4HyuQPBpu-4xjmQC&q=85&s=91083bf83a4c03ea40d485b23f072259" width="1380" height="941" data-path="images/docs/d4674261847231079fecc176ba88065409c90943e3854b9df200457325a0aed4-Screenshot_2025-03-18_at_14.47.25.png" />
</Frame>

我们可以创建一个等级在 5 到 10 之间的用户分组，并使用它来发送有针对性的个性化消息：

<Frame caption="分组编辑器显示针对 current_level 值大于 4 且小于 10 的用户的分组">
  <img src="https://mintcdn.com/onesignal/3zq1PvSaqvUE2bIx/images/docs/300d36b632a6f6d7017780457bbe2610b71767fd0db093c7611e59714dcbda5b-Screenshot_2025-03-18_at_14.49.56.png?fit=max&auto=format&n=3zq1PvSaqvUE2bIx&q=85&s=b84ab0d2c6eedbd6d4e7a2bf15afe103" width="1380" height="941" data-path="images/docs/300d36b632a6f6d7017780457bbe2610b71767fd0db093c7611e59714dcbda5b-Screenshot_2025-03-18_at_14.49.56.png" />
</Frame>

<br />

<Frame caption="屏幕截图显示针对 5-10 级分组发送的个性化推送通知">
  <img src="https://mintcdn.com/onesignal/tc0EvmtSSX56SX0c/images/docs/97e09b42d25c6d3f4c7cb0a6fff4dfb8893cbb4b283f7ff1f77977c33113319c-Screenshot_2025-03-18_at_14.55.47.png?fit=max&auto=format&n=tc0EvmtSSX56SX0c&q=85&s=c7839b12057d65a12a4eaddce6e2c11f" width="2764" height="2286" data-path="images/docs/97e09b42d25c6d3f4c7cb0a6fff4dfb8893cbb4b283f7ff1f77977c33113319c-Screenshot_2025-03-18_at_14.55.47.png" />
</Frame>

<br />

<Frame caption="iOS 和 Android 设备上收到的包含个性化内容的推送通知">
  <img src="https://mintcdn.com/onesignal/_KaXe4GQkxsEfa17/images/docs/3bf1810580f30984745017056383f151b874513b6bfb1445fb1016e5c9a79e82-Untitled_design_12.png?fit=max&auto=format&n=_KaXe4GQkxsEfa17&q=85&s=94b6e9eeeb5516285a256a72063a0906" width="1920" height="1080" data-path="images/docs/3bf1810580f30984745017056383f151b874513b6bfb1445fb1016e5c9a79e82-Untitled_design_12.png" />
</Frame>

### 添加电子邮件和/或短信订阅

之前我们了解了我们的 SDK 如何创建移动端订阅来发送推送和应用内消息。您还可以通过创建相应的订阅，通过电子邮件和短信渠道联系用户。

* 使用[`addEmail` 方法](/docs/cn/mobile-sdk-reference#addemail-%2C-removeemail)创建电子邮件订阅。
* 使用[`addSms` 方法](/docs/cn/mobile-sdk-reference#addsms-%2C-removesms)创建短信订阅。

如果电子邮件地址和/或电话号码在 OneSignal 应用中已存在，SDK 会将其添加到现有用户，不会创建重复项。

您可以通过控制台中的 **受众 > 用户** 或使用[查看用户 API](/reference/view-user)查看统一的用户。

<Frame caption="通过外部 ID 统一的包含推送、电子邮件和短信订阅的用户档案">
  <img src="https://mintcdn.com/onesignal/56ctKxZSV4m5VEkn/images/docs/b1cf9999d41da6e4ce333e1126612529b85eac47447bb0b434418d082f595acd-Screenshot_2025-03-18_at_14.43.46.png?fit=max&auto=format&n=56ctKxZSV4m5VEkn&q=85&s=7c3885b66e44e097fa0ed7c47f27c911" width="1506" height="848" data-path="images/docs/b1cf9999d41da6e4ce333e1126612529b85eac47447bb0b434418d082f595acd-Screenshot_2025-03-18_at_14.43.46.png" />
</Frame>

<Note>
  多渠道沟通的最佳实践

  * 在添加电子邮件或短信订阅之前获得明确同意。
  * 向用户解释每个沟通渠道的好处。
  * 提供渠道偏好，让用户可以选择他们偏好的渠道。
</Note>

***

### 隐私和用户同意

要控制 OneSignal 何时收集用户数据，请使用 SDK 的同意管控方法：

* [`setConsentRequired(true)`](/docs/cn/mobile-sdk-reference#setconsentrequired)：阻止数据收集直到获得同意。
* [`setConsentGiven(true)`](/docs/cn/mobile-sdk-reference#setconsentgiven)：一旦获得同意即启用数据收集。

有关更多信息，请参阅我们的隐私和安全文档：

* [SDK 收集的数据](/docs/cn/data-collected-by-the-onesignal-sdk)
* [处理个人数据](/docs/cn/handling-personal-data)

***

## 提示推送权限

不要在应用打开时立即调用 `requestPermission()`，而是采取更策略性的方法。在请求权限之前，使用应用内消息解释推送通知的价值。

有关最佳实践和实现细节，请参阅我们的[提示推送权限](/docs/cn/prompt-for-push-permissions)指南。

***

## 监听推送、用户和应用内事件

使用 SDK 监听器来响应用户操作和状态变化。

SDK 提供了几个事件监听器供您使用。更多详情请参阅我们的[SDK 参考指南](/docs/cn/mobile-sdk-reference)。

### 推送通知事件

* [`addClickListener()`](/docs/cn/mobile-sdk-reference#addclicklistener-push)：检测通知被点击时。对[深度链接](/docs/cn/deep-linking)有帮助。
* [`addForegroundLifecycleListener()`](/docs/cn/mobile-sdk-reference#addforegroundlifecyclelistener-push)：控制通知在前台的行为方式。

要进行完全自定义，请参阅[移动端服务扩展](/docs/cn/service-extensions)。

### 用户状态变化

* [`addObserver()` 用于用户状态](/docs/cn/mobile-sdk-reference#addobserver-user-state)：检测外部 ID 设置时。
* [`addPermissionObserver()`](/docs/cn/mobile-sdk-reference#addpermissionobserver-push)：跟踪用户与原生推送权限提示的特定交互。
* [`addObserver()` 用于推送订阅](/docs/cn/mobile-sdk-reference#addobserver-push-subscription-changes)：跟踪推送订阅状态变化时。

### 应用内消息事件

* [`addClickListener()`](/docs/cn/mobile-sdk-reference#addclicklistener-in-app)：处理应用内点击操作。适用于深度链接或跟踪事件。
* [`addLifecycleListener()`](/docs/cn/mobile-sdk-reference#addclicklistener-in-app)：跟踪应用内消息的完整生命周期（显示、点击、关闭等）。

***

## 高级设置和功能

探索更多功能以增强您的集成：

* [🔁 从其他服务迁移到 OneSignal](/docs/cn/migrating-to-onesignal)
* [🌍 位置跟踪](/docs/cn/mobile-sdk-reference#location)
* [🔗 深度链接](/docs/cn/deep-linking)
* [🔌 集成](/docs/cn/integrations)
* [🧩 移动端服务扩展](/docs/cn/service-extensions)
* [🛎️ 操作按钮](/docs/cn/action-buttons)
* [🌐 多语言消息](/docs/cn/multi-language-messaging)
* [🛡️ 身份验证](/docs/cn/identity-verification)
* [📊 自定义结果](/docs/cn/custom-outcomes)
* [📲 Live Activities](/docs/cn/live-activities)

### 移动端 SDK 设置和参考

通过查看[移动端推送设置](/docs/cn/mobile-push-setup)指南，确保您已启用所有关键功能。

有关可用方法和配置选项的完整详细信息，请访问[移动端 SDK 参考](/docs/cn/mobile-sdk-reference)。

<Check>恭喜！您已成功完成移动端 SDK 设置指南。</Check>

***

<Info>
  需要帮助？

  与我们的支持团队聊天或发送邮件至 `support@onesignal.com`

  请包含以下信息：

  * 您遇到的问题详情以及复现步骤（如有）
  * 您的 OneSignal 应用 ID
  * 外部 ID 或订阅 ID（如适用）
  * 您在 OneSignal 控制台中测试的消息 URL（如适用）
  * 任何相关的[日志或错误信息](/docs/cn/capturing-a-debug-log)

  我们很乐意为您提供帮助！
</Info>

***
