> ## 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.

# Ionic/Cordova/Capacitor SDK 设置

> 为您的 Ionic 或 Capacitor 应用添加 OneSignal SDK 的说明，支持 iOS、Android、Amazon Fire 应用

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="cordova" viewMode="mini" />

## 概览

本指南解释了如何将 OneSignal 推送通知集成到 Ionic、Capacitor 或 Cordova 应用程序中。它涵盖了从安装到配置和服务工作器管理的所有内容。

<Note>
  正在构建 Capacitor 应用？我们强烈建议改用 [Capacitor SDK 设置](./capacitor-sdk-setup)指南。仅当您的 Capacitor 项目必须使用 Cordova 插件以兼容现有 Cordova 代码时，才使用此 Cordova 设置。
</Note>

***

## 要求

<Tabs>
  <Tab title="Cordova">
    * Cordova v10+（设置说明使用 v12）
    * 已配置的 OneSignal 应用和平台
  </Tab>

  <Tab title="Ionic/Capacitor">
    * Ionic v7+（设置说明使用 v7.2.1）
    * Capacitor v5+（设置说明使用 v7.2.0）
    * 已配置的 OneSignal 应用和平台
  </Tab>
</Tabs>

**iOS 要求**

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

**Android 要求**

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

<Warning>
  应用名称不应包含空格（例如，使用"MyApp"而不是"My App"）以避免构建问题
</Warning>

### 配置您的 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

将 `onesignal-cordova-plugin` 包添加到您的项目中。

<CodeGroup>
  ```shell Cordova theme={null}
  cordova plugin add onesignal-cordova-plugin
  ```

  ```shell Ionic/Capacitor theme={null}
  npm install onesignal-cordova-plugin
  npx cap sync
  ```
</CodeGroup>

### iOS 原生依赖项

从 `onesignal-cordova-plugin` 5.5.0 开始，使用 `cordova-ios` 8 或更高版本的 Cordova iOS 应用可以通过 Swift Package Manager (SPM) 解析 OneSignal 的原生 iOS 依赖项。较旧的 Cordova iOS 应用会继续通过 `OneSignalCordovaDependencies` 使用 CocoaPods。

使用此 Cordova 插件并启用 SPM 的 Capacitor 应用需要 Capacitor 8.4.0 或更高版本，以便 Capacitor 可以读取插件根目录中的 `Package.swift`。对于新的 Capacitor iOS 项目，请使用 `npx cap add ios --packagemanager SPM` 创建原生平台，然后在安装插件后运行 `npx cap sync ios`。

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

从 `onesignal-cordova-plugin` 5.4.0 开始，如果您的应用不使用 `OneSignal.Location`，您可以从 Android、iOS CocoaPods 和 iOS Swift Package Manager 构建中排除 OneSignal 的原生位置模块。

在安装插件或同步原生平台之前设置 `ONESIGNAL_DISABLE_LOCATION=true`。该值不区分大小写。您也可以将其设置为 `1`。对于 iOS Swift Package Manager，请在实际 Xcode 构建过程中保持该标志已设置，以便 `Package.swift` 在禁用位置模块的情况下求值。

<CodeGroup>
  ```shell Cordova theme={null}
  ONESIGNAL_DISABLE_LOCATION=true cordova plugin add onesignal-cordova-plugin
  ONESIGNAL_DISABLE_LOCATION=true cordova platform add ios
  ONESIGNAL_DISABLE_LOCATION=true cordova platform add android
  ```

  ```shell Capacitor theme={null}
  ONESIGNAL_DISABLE_LOCATION=true npx cap sync ios
  ONESIGNAL_DISABLE_LOCATION=true npx cap sync android
  ONESIGNAL_DISABLE_LOCATION=true npx cap run ios --no-sync
  ```

  ```yaml GitHub Actions theme={null}
  env:
    ONESIGNAL_DISABLE_LOCATION: true
  ```
</CodeGroup>

禁用位置模块后，对 `OneSignal.Location` 的调用会被忽略。`OneSignal.Location.isShared()` 会解析为 `false`。

#### 在原生依赖项已缓存后应用更改

环境变量会在解析原生依赖项时读取。如果您在现有项目中更改该变量，请清除相关原生依赖项状态，并在已导出该变量的 shell 中重新解析。

<CodeGroup>
  ```shell Cordova theme={null}
  cd platforms/ios
  pod deintegrate
  rm -rf Pods Podfile.lock
  ONESIGNAL_DISABLE_LOCATION=true pod install
  ```

  ```shell Capacitor theme={null}
  cd ios/App
  pod deintegrate
  rm -rf Pods Podfile.lock
  ONESIGNAL_DISABLE_LOCATION=true pod install
  ```

  ```shell Swift Package Manager theme={null}
  rm -rf ios/App/App.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
  ONESIGNAL_DISABLE_LOCATION=true xcodebuild \
    -resolvePackageDependencies \
    -project ios/App/App.xcodeproj \
    -derivedDataPath ios/App/build
  ONESIGNAL_DISABLE_LOCATION=true xcodebuild \
    -project ios/App/App.xcodeproj \
    -scheme App \
    -derivedDataPath ios/App/build
  ```
</CodeGroup>

<Warning>
  使用 Xcode 或 Android Studio 时，请从已导出 `ONESIGNAL_DISABLE_LOCATION` 的终端启动 IDE。在 CI 上，请根据 `ONESIGNAL_DISABLE_LOCATION` 的值为 DerivedData、Swift Package Manager、CocoaPods 和 Gradle 缓存设置键。
</Warning>

### 2. 初始化 SDK

根据您项目的框架 Cordova 和/或 Ionic 或 Ionic 和 Capacitor，按照提供的说明初始化 OneSignal。

<Accordion title="Ionic + Capacitor 的说明">
  * **Angular**：在您的 `src/app/app.component.ts` 文件中使用提供的方法初始化 OneSignal。
  * **React**：在您的 `src/App.tsx` 或 `src/index.tsx` 文件中使用提供的方法初始化 OneSignal。
  * **Vue**：在您的 `src/main.ts` 文件中使用提供的方法初始化 OneSignal。

  将 `YOUR_APP_ID` 替换为您在 OneSignal 仪表板 **设置 > [密钥和 ID](./keys-and-ids)** 中找到的 OneSignal 应用 ID。

  <Note>
    如果您无法访问 OneSignal 应用，请要求您的[团队成员](./manage-team-members)邀请您。
  </Note>

  <CodeGroup>
    ```typescript Angular theme={null}
    import OneSignal, { LogLevel } from 'onesignal-cordova-plugin';

    @Component({
      selector: 'app-root',
      templateUrl: 'app.component.html',
      styleUrls: ['app.component.scss'],
    })
    export class AppComponent {
      constructor() {

          // Enable verbose logging for debugging (remove in production)
          OneSignal.Debug.setLogLevel(LogLevel.Verbose);
          // Initialize with your OneSignal App ID
          OneSignal.initialize("YOUR_APP_ID");
          // Use this method to prompt for push notifications.
          // We recommend removing this method after testing and instead use In-App Messages to prompt for notification permission.
          OneSignal.Notifications.requestPermission(false).then((accepted: boolean) => {
            console.log("User accepted notifications: " + accepted);
          });

      }
    }
    ```

    ```typescript React theme={null}
    import { useEffect } from 'react';
    import OneSignal, { LogLevel } from 'onesignal-cordova-plugin';

    const App: React.FC = () => {
      useEffect(() => {
        // Enable verbose logging for debugging (remove in production)
        OneSignal.Debug.setLogLevel(LogLevel.Verbose);
        // Initialize with your OneSignal App ID
        OneSignal.initialize("YOUR_APP_ID");
        // Use this method to prompt for push notifications.
        // We recommend removing this method after testing and instead use In-App Messages to prompt for notification permission.
        OneSignal.Notifications.requestPermission(false).then((accepted: boolean) => {
          console.log("User accepted notifications: " + accepted);
        });
      }, []);
    };
    ```

    ```typescript Vue theme={null}
    import { createApp } from 'vue';
    import App from './App.vue';
    import router from './router';
    import OneSignal, { LogLevel } from 'onesignal-cordova-plugin';
    import { IonicVue } from '@ionic/vue';

    const app = createApp(App)
      .use(IonicVue)
      .use(router);

    router.isReady().then(() => {
      app.mount('#app');

      // Enable verbose logging for debugging (remove in production)
      OneSignal.Debug.setLogLevel(LogLevel.Verbose);
      // Initialize with your OneSignal App ID
      OneSignal.initialize("YOUR_APP_ID");
      // Use this method to prompt for push notifications.
      // We recommend removing this method after testing and instead use In-App Messages to prompt for notification permission.
      OneSignal.Notifications.requestPermission(false).then((accepted: boolean) => {
        console.log("User accepted notifications: " + accepted);
      });

    });
    ```
  </CodeGroup>

  打开您的 `capacitor.config.json` 或 `capacitor.config.ts` 并添加以下代码以允许 OneSignal 处理 iOS 推送通知。

  <Note>
    如果订阅失败并出现"APNS Delegate Never Fired"错误，此配置将解决该问题。
  </Note>

  <CodeGroup>
    ```json json theme={null}
    {
      "ios": {
        "handleApplicationNotifications": false
      }
    }
    ```

    ```typescript capacitor.config.ts theme={null}
    const config: CapacitorConfig = {
      // ... additional configuration

      ios: {
        // ... additional configuration
        handleApplicationNotifications: false
      }
    };
    ```
  </CodeGroup>
</Accordion>

<Accordion title="Ionic + Cordova 的说明">
  在您的 `src/app/app.component.ts` 文件中使用提供的方法初始化 OneSignal。

  将 `YOUR_APP_ID` 替换为您在 OneSignal 仪表板 **设置 > [密钥和 ID](./keys-and-ids)** 中找到的 OneSignal 应用 ID。

  <Note>
    如果您无法访问 OneSignal 应用，请要求您的[团队成员](./manage-team-members)邀请您。
  </Note>

  <CodeGroup>
    ```typescript typescript theme={null}
    import OneSignal, { LogLevel } from 'onesignal-cordova-plugin';

    constructor(platform: Platform) {
        platform.ready().then(() => {

          // Enable verbose logging for debugging (remove in production)
          OneSignal.Debug.setLogLevel(LogLevel.Verbose);
          // Initialize with your OneSignal App ID
          OneSignal.initialize("YOUR_APP_ID");
          // Use this method to prompt for push notifications.
          // We recommend removing this method after testing and instead use In-App Messages to prompt for notification permission.
          OneSignal.Notifications.requestPermission(false).then((accepted: boolean) => {
            console.log("User accepted notifications: " + accepted);
          });

        });
      }
    ```
  </CodeGroup>
</Accordion>

<Accordion title="Cordova 的说明">
  在您的 `www/js/index.js` 文件中使用提供的方法初始化 OneSignal。

  将 `YOUR_APP_ID` 替换为您在 OneSignal 仪表板 **设置 > [密钥和 ID](./keys-and-ids)** 中找到的 OneSignal 应用 ID。

  <Note>
    如果您无法访问 OneSignal 应用，请要求您的[团队成员](./manage-team-members)邀请您。
  </Note>

  <CodeGroup>
    ```javascript index.js theme={null}
    document.addEventListener('deviceready', onDeviceReady, false);

    function onDeviceReady() {

        // Enable verbose logging for debugging (remove in production)
        window.plugins.OneSignal.Debug.setLogLevel(6);
        // Initialize with your OneSignal App ID
        window.plugins.OneSignal.initialize('YOUR_APP_ID');
        // Use this method to prompt for push notifications.
        // We recommend removing this method after testing and instead use In-App Messages to prompt for notification permission.
        window.plugins.OneSignal.Notifications.requestPermission(false).then((accepted) => {
          console.log("User accepted notifications: " + accepted);
        });

    }
    ```
  </CodeGroup>
</Accordion>

***

## 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 设置

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

按照以下步骤向您的 iOS 应用添加推送通知，包括对[徽章](/docs/cn/badges)、[确认送达](/docs/cn/confirmed-delivery) 和图像的支持。

### 1. 向应用目标添加推送通知功能

[推送通知功能](https://developer.apple.com/documentation/UserNotifications/registering-your-app-with-apns#Enable-the-push-notifications-capability) 允许您的应用注册推送令牌并接收通知。

1. 在 Xcode 中打开您的应用的 `.xcworkspace` 文件。
2. 选择 **您的应用目标 > 签名和功能**
3. 点击 **+ 功能** 并添加 **推送通知** 功能

<Frame caption="为应用目标添加推送通知功能。">
  <img src="https://mintcdn.com/onesignal/9_Q1FZLh6C0BFLq-/images/docs/c44118529490f1a7a1245a4c1e8b525d9eb23ab430f035b26b426889fc0486b6-382d57ff7ce1023a863da9f18a97b9a643b1e4b172ec02f1b6661160c362d827-Screenshot_2025-03-10_at_11.19.03_AM.png?fit=max&auto=format&n=9_Q1FZLh6C0BFLq-&q=85&s=e4475a29ab479ec1bd151c809bebd26a" width="2436" height="1324" data-path="images/docs/c44118529490f1a7a1245a4c1e8b525d9eb23ab430f035b26b426889fc0486b6-382d57ff7ce1023a863da9f18a97b9a643b1e4b172ec02f1b6661160c362d827-Screenshot_2025-03-10_at_11.19.03_AM.png" />
</Frame>

### 2. 向应用目标添加后台模式功能

这使您的应用能够在推送通知到达时在后台唤醒。

1. 添加[后台模式](https://developer.apple.com/documentation/usernotifications/pushing-background-updates-to-your-app)功能
2. 启用 **远程通知**

<Frame caption="为应用目标添加远程通知后台执行模式。">
  <img src="https://mintcdn.com/onesignal/YOTSrtBSoqdrJ37A/images/docs/498bd555602023bd8f3ba8e7ee58c8f58eb260accd2f941f64e3e5de07ad99d8-Screenshot_2025-03-10_at_11.20.58_AM.png?fit=max&auto=format&n=YOTSrtBSoqdrJ37A&q=85&s=79995d23ebbcb67d6a2bd0412259f8c0" width="2436" height="1324" data-path="images/docs/498bd555602023bd8f3ba8e7ee58c8f58eb260accd2f941f64e3e5de07ad99d8-Screenshot_2025-03-10_at_11.20.58_AM.png" />
</Frame>

### 3. 将应用目标添加到应用组

[应用组](https://developer.apple.com/documentation/xcode/configuring-app-groups/#Create-App-Groups-for-all-other-platforms) 允许您的应用和通知服务扩展之间进行数据共享。这是确认送达和徽章功能所必需的。

<Tabs>
  <Tab title="如果您尚未配置应用组">
    1. 添加 **应用组** 功能
    2. 在应用组功能中点击 **+**
    3. 添加格式为 `group.your_bundle_id.onesignal` 的新容器 ID

    * 保留 **group.** 和 **.onesignal** 前缀和后缀。将 **`your_bundle_id`** 替换为您应用的包标识符。
    * 例如，包标识符 `com.onesignal.MyApp`，将具有容器名称 `group.com.onesignal.MyApp.onesignal`。

    <Frame caption="应用目标是应用组的一部分。">
      <img src="https://mintcdn.com/onesignal/_KaXe4GQkxsEfa17/images/docs/34e545ae24b0fbdf043fd587102f7039cd1daf65777e84690946f4fb20f739aa-Screenshot_2025-03-10_at_11.22.52_AM.png?fit=max&auto=format&n=_KaXe4GQkxsEfa17&q=85&s=5904f8a6dd4030f5ee7cfa82b3c3eeb8" width="2436" height="1324" data-path="images/docs/34e545ae24b0fbdf043fd587102f7039cd1daf65777e84690946f4fb20f739aa-Screenshot_2025-03-10_at_11.22.52_AM.png" />
    </Frame>

    <Warning> 您的应用组名称必须与所有目标中的包 ID 拼写和大小写完全匹配。 </Warning>
  </Tab>

  <Tab title="如果您已有应用组">
    1. 打开您应用的 `Info.plist`
    2. 添加新属性：

    * **键：** `OneSignal_app_groups_key`
    * **值：** 您现有的应用组名称（例如，`group.com.example.mycustomgroup`）

    ```xml XML theme={null}
    <key>OneSignal_app_groups_key</key>
    <string>group.com.example.mycustomgroup</string>
    ```

    <Frame caption="在应用目标内设置的自定义应用组。">
      <img src="https://mintcdn.com/onesignal/RWtLFPeffHrC81wI/images/docs/aa3a061cbf89856a5ee75737e24a3dc7b36e96a866d277e68a170f136cbeae48-Screenshot_2025-03-10_at_11.24.56_AM.png?fit=max&auto=format&n=RWtLFPeffHrC81wI&q=85&s=84e93061a8c82c1ca44cc14b81995d46" width="2788" height="1400" data-path="images/docs/aa3a061cbf89856a5ee75737e24a3dc7b36e96a866d277e68a170f136cbeae48-Screenshot_2025-03-10_at_11.24.56_AM.png" />
    </Frame>
  </Tab>
</Tabs>

### 4. 添加通知服务扩展

[通知服务扩展 (NSE)](https://developer.apple.com/documentation/usernotifications/modifying-content-in-newly-delivered-notifications) 启用丰富通知和确认送达分析功能。

1. 在 Xcode 中：**File > New > Target...**
2. 选择 **Notification Service Extension**，然后点击 **Next**。
3. 将产品名称设置为 `OneSignalNotificationServiceExtension` 并按 **Finish**。
4. 在激活方案提示上按 **Don't Activate**。

<Frame caption="选择通知服务扩展目标。">
  <img src="https://mintcdn.com/onesignal/_KaXe4GQkxsEfa17/images/docs/3ba0018a789c52c5c8d2f485d31e0ba0e07398d7abf5980215e4d4d2a2e0e948-Screenshot_2025-03-10_at_11.27.24_AM.png?fit=max&auto=format&n=_KaXe4GQkxsEfa17&q=85&s=c5c5399c449ec5201dfb3342f9eeb538" width="2788" height="1400" data-path="images/docs/3ba0018a789c52c5c8d2f485d31e0ba0e07398d7abf5980215e4d4d2a2e0e948-Screenshot_2025-03-10_at_11.27.24_AM.png" />
</Frame>

<Frame caption="为通知服务扩展命名。">
  <img src="https://mintcdn.com/onesignal/RWtLFPeffHrC81wI/images/docs/afb3452c5ef95511c7ca4ef50c36ea2e5c205030c35d7ea066270a40f9ec3234-Screenshot_2025-03-10_at_11.27.47_AM.png?fit=max&auto=format&n=RWtLFPeffHrC81wI&q=85&s=ed78140e080cf8aad1e727d819bac8ad" width="2788" height="1400" data-path="images/docs/afb3452c5ef95511c7ca4ef50c36ea2e5c205030c35d7ea066270a40f9ec3234-Screenshot_2025-03-10_at_11.27.47_AM.png" />
</Frame>

<Frame caption="取消激活以继续调试您的应用目标。">
  <img src="https://mintcdn.com/onesignal/4HyuQPBpu-4xjmQC/images/docs/cfc756b0273e5973af42a4a2933f3efcb5c4aeaf7ca5cec6bd196e8c01250f62-Screenshot_2025-03-10_at_11.28.01_AM.png?fit=max&auto=format&n=4HyuQPBpu-4xjmQC&q=85&s=03f43bf27f643419eba14e438f3f07a1" width="2788" height="1400" data-path="images/docs/cfc756b0273e5973af42a4a2933f3efcb5c4aeaf7ca5cec6bd196e8c01250f62-Screenshot_2025-03-10_at_11.28.01_AM.png" />
</Frame>

将 OneSignalNotificationServiceExtension 的 **最低部署目标** 设置为与主应用匹配（推荐 iOS 15+）。

<Info> 如果您使用的是 CocoaPods，请同时在您的 Podfile 中设置部署版本。 </Info>

<Frame caption="设置与主应用相同的部署目标。">
  <img src="https://mintcdn.com/onesignal/tNi1OgLc_p9hiq7_/images/docs/17cc605c99d890e50e83e45bfbe89ce5c7b226b6b000b9aa739d70a1bf41c231-Screenshot_2025-03-10_at_11.29.35_AM.png?fit=max&auto=format&n=tNi1OgLc_p9hiq7_&q=85&s=48f72f24a321d60e6623b440b591987a" width="2788" height="1400" data-path="images/docs/17cc605c99d890e50e83e45bfbe89ce5c7b226b6b000b9aa739d70a1bf41c231-Screenshot_2025-03-10_at_11.29.35_AM.png" />
</Frame>

### 5. 将 NSE 目标添加到应用组

使用您在第 3 步中添加的相同应用组 ID。

1. 转到 **OneSignalNotificationServiceExtension > Signing & Capabilities**
2. 添加 **App Groups**
3. 添加完全相同的组 ID

<Frame caption="NSE 现在与您的应用目标属于同一个应用组。">
  <img src="https://mintcdn.com/onesignal/Xl2NHJvxakrK4JbL/images/docs/e763a62e9ab8457d16fbb9a2c1f9344bb73a5a5d40fa920bbba18e040128a229-Screenshot_2025-03-10_at_11.30.24_AM.png?fit=max&auto=format&n=Xl2NHJvxakrK4JbL&q=85&s=096adcb29f4d4d61bf51a0b9caed695d" width="2788" height="1400" data-path="images/docs/e763a62e9ab8457d16fbb9a2c1f9344bb73a5a5d40fa920bbba18e040128a229-Screenshot_2025-03-10_at_11.30.24_AM.png" />
</Frame>

### 6. 更新 NSE 代码

1. 导航到 **OneSignalNotificationServiceExtension** 文件夹
2. 将 `NotificationService.swift` 或 `NotificationService.m` 文件的内容替换为以下内容：

<Frame caption="导航到您的 NotificationService 文件。">
  <img src="https://mintcdn.com/onesignal/RWtLFPeffHrC81wI/images/docs/ab43a237c660116a9547fe9b53ab2594181f6c04297b5a7236d21764122d26b3-Screenshot_2025-03-10_at_11.31.52_AM.png?fit=max&auto=format&n=RWtLFPeffHrC81wI&q=85&s=917ea1a94b0485f5f14d3fe8d28886d4" width="2788" height="1400" data-path="images/docs/ab43a237c660116a9547fe9b53ab2594181f6c04297b5a7236d21764122d26b3-Screenshot_2025-03-10_at_11.31.52_AM.png" />
</Frame>

<CodeGroup>
  ```swift Swift theme={null}
  import UserNotifications
  import OneSignalExtension

  class NotificationService: UNNotificationServiceExtension {
      var contentHandler: ((UNNotificationContent) -> Void)?
      var receivedRequest: UNNotificationRequest!
      var bestAttemptContent: UNMutableNotificationContent?

      // Note this extension only runs when `mutable_content` is set
      // Setting an attachment or action buttons automatically sets the property to true
      override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
          self.receivedRequest = request
          self.contentHandler = contentHandler
          self.bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)

          if let bestAttemptContent = bestAttemptContent {
              // DEBUGGING: Uncomment the 2 lines below to check this extension is executing
  //            print("Running NotificationServiceExtension")
  //            bestAttemptContent.body = "[Modified] " + bestAttemptContent.body

              OneSignalExtension.didReceiveNotificationExtensionRequest(self.receivedRequest, with: bestAttemptContent, withContentHandler: self.contentHandler)
          }
      }

      override func serviceExtensionTimeWillExpire() {
          // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
          if let contentHandler = contentHandler, let bestAttemptContent =  bestAttemptContent {
              OneSignalExtension.serviceExtensionTimeWillExpireRequest(self.receivedRequest, with: self.bestAttemptContent)
              contentHandler(bestAttemptContent)
          }
      }
  }
  ```

  ```objectivec Objective-C theme={null}
  #import <OneSignalExtension/OneSignalExtension.h>
  #import "NotificationService.h"

  @interface NotificationService ()

  @property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
  @property (nonatomic, strong) UNNotificationRequest *receivedRequest;
  @property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;

  @end

  @implementation NotificationService

  // Note, this extension only runs when mutable-content is set
  // Setting an attachment or action buttons automatically adds this
  - (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
      self.receivedRequest = request;
      self.contentHandler = contentHandler;
      self.bestAttemptContent = [request.content mutableCopy];

      // DEBUGGING: Uncomment the 2 lines below and comment out the one above to ensure this extension is executing
  //     NSLog(@"Running NotificationServiceExtension");
  //     self.bestAttemptContent.body = [@"[Modified] " stringByAppendingString:self.bestAttemptContent.body];

      [OneSignalExtension didReceiveNotificationExtensionRequest:self.receivedRequest
                         withMutableNotificationContent:self.bestAttemptContent
                                     withContentHandler:self.contentHandler];
  }

  - (void)serviceExtensionTimeWillExpire {
      // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.

      [OneSignalExtension serviceExtensionTimeWillExpireRequest:self.receivedRequest withMutableNotificationContent:self.bestAttemptContent];

      self.contentHandler(self.bestAttemptContent);
  }

  @end
  ```
</CodeGroup>

您应该会看到错误，因为 OneSignal 包尚未安装。这将在下一步中解决。

<Frame caption="在下一步中安装包之前，此文件会显示错误。">
  <img src="https://mintcdn.com/onesignal/4HyuQPBpu-4xjmQC/images/docs/d3d8900d922b3bcaa44c0012e152ca233404d4c80d8bd427792c456aab798d06-Screenshot_2025-03-10_at_11.32.12_AM.png?fit=max&auto=format&n=4HyuQPBpu-4xjmQC&q=85&s=11c4114e117cb74099d9a063d6d11ebc" width="2788" height="1400" data-path="images/docs/d3d8900d922b3bcaa44c0012e152ca233404d4c80d8bd427792c456aab798d06-Screenshot_2025-03-10_at_11.32.12_AM.png" />
</Frame>

### 7. 将 OneSignal 添加到 NSE 目标

<Note>
  如果您的 SDK 使用 Swift Package Manager (SPM) 管理 iOS 依赖项，可以跳过此步骤。OneSignal 包已解析并可供所有目标使用。
</Note>

更新您的 `ios/Podfile` 以包含：

<CodeGroup>
  ```ruby Podfile theme={null}
  target 'OneSignalNotificationServiceExtension' do
    pod 'OneSignalXCFramework', '>= 5.0.0', '< 6.0'
  end
  ```

  ```ruby Example theme={null}
  target 'MyApp' do
    config = use_native_modules!

    use_react_native!(
      :path => config[:reactNativePath],
      # An absolute path to your application root.
      :app_path => "#{Pod::Config.instance.installation_root}/.."
    )

    post_install do |installer|
      # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202
      react_native_post_install(
        installer,
        config[:reactNativePath],
        :mac_catalyst_enabled => false,
        # :ccache_enabled => true
      )
    end
  end

  target 'OneSignalNotificationServiceExtension' do
    pod 'OneSignalXCFramework', '>= 5.0.0', '< 6.0'
  end
  ```
</CodeGroup>

在终端中打开您的项目并运行：

```shell shell  theme={null}
cd ios pod install cd .. 
```

#### 常见的 pod install 错误

您可能会遇到以下错误，以下是解决方法。

<Accordion title="ArgumentError - \[Xcodeproj] 无法找到对象版本 `70` 的兼容性版本字符串。">
  CocoaPods 依赖 `xcodeproj` Ruby gem 来读取您的 Xcode 项目文件。截至目前，最新的 `xcodeproj` 版本不识别 Xcode 16 引入的对象版本 70。因此，当 CocoaPods 尝试打开您的 `.xcodeproj` 文件时，它会因为这个错误而崩溃。

  1. 关闭 Xcode。
  2. 导航到您项目的 `ios/<your-app>.xcodeproj/project.pbxproj` 文件。
  3. 更改这一行：`objectVersion = 70;`
  4. 将其替换为：`objectVersion = 55;`
  5. 保存、关闭，并重新运行 `cd ios pod install cd ..`
</Accordion>

### 为 iOS 构建

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

#### 常见的 iOS 构建错误

<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>

  修复：

  1. 找到错误中在 "path" 下列出的文件夹
  2. 在 Xcode 项目侧边栏中，右键单击该文件夹
  3. 选择 **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>

***
