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

# Flutterflow SDK 设置

> 在您的 Flutterflow iOS 和 Android 应用程序中添加 OneSignal Flutter SDK 的说明

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

本指南适用于 Flutterflow 移动应用程序设置。如果您有 Flutterflow 网站，请查看我们的 [Web SDK 设置](./web-sdk-setup) 指南。

## 要求

* Flutterflow 计划：标准版或更高版本
* 已配置的 OneSignal 应用程序和平台

**iOS 要求**

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

**Android 要求**

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

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

***

## 设置

### 1. 创建新的自定义操作

在您的 Flutterflow 项目中，导航到自定义代码，然后单击 +Add 按钮并选择操作。

<Frame>
  <img src="https://mintcdn.com/onesignal/Xl2NHJvxakrK4JbL/images/docs/f6a30014959335e895c0b3ce51eb78ea3dbae10a092461df7b390fe9862e43d3-Screenshot_2024-09-09_at_16.30.54.png?fit=max&auto=format&n=Xl2NHJvxakrK4JbL&q=85&s=449ba1ba0cc5255a75876ed041baf6ab" width="440" height="654" data-path="images/docs/f6a30014959335e895c0b3ce51eb78ea3dbae10a092461df7b390fe9862e43d3-Screenshot_2024-09-09_at_16.30.54.png" />
</Frame>

在右侧工具栏的操作设置下，单击添加依赖项并输入以下依赖项，然后单击刷新将其添加到操作中：

```yaml dependency theme={null}
  dependencies:
  	onesignal_flutter: ^5.1.2
```

<Frame>
  <img src="https://mintcdn.com/onesignal/4HyuQPBpu-4xjmQC/images/docs/cc2adb5fd282176c331cd6684ccc4afcec48c9e6d1d5c172f79196b19beb2c05-Screenshot_2024-09-09_at_16.30.18.png?fit=max&auto=format&n=4HyuQPBpu-4xjmQC&q=85&s=a16a21ea7f62669dc8498b246b53dfde" width="341" height="200" data-path="images/docs/cc2adb5fd282176c331cd6684ccc4afcec48c9e6d1d5c172f79196b19beb2c05-Screenshot_2024-09-09_at_16.30.18.png" />
</Frame>

在操作代码中，在预加载的代码下添加以下内容，然后保存并编译您的操作。

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

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

```javascript Flutter theme={null}
  import 'package:onesignal_flutter/onesignal_flutter.dart';

  Future onesignal() async {
    //Remove this method to stop OneSignal Debugging
    OneSignal.Debug.setLogLevel(OSLogLevel.verbose);

    OneSignal.initialize("YOUR_APP_ID");

    // The promptForPushNotificationsWithUserResponse function will show the iOS or Android push notification prompt. We recommend removing the following code and instead using an In-App Message to prompt for notification permission
    OneSignal.Notifications.requestPermission(true);
  }
```

接下来，单击左侧工具栏中的 main.dart 文件，然后单击右侧栏中初始操作旁边的 + 图标，并单击刚刚创建的 `onesignal` 操作。

<Frame>
  <img src="https://mintcdn.com/onesignal/jFWn5xzleD8du3j6/images/docs/61ef594d0a96baa53c5d0eebb714b1c823dfe2bd31233fa8be75f6a98d1dc79e-Screenshot_2024-09-09_at_16.34.14.png?fit=max&auto=format&n=jFWn5xzleD8du3j6&q=85&s=b98847b383abbaaa876f4f30f372a9bc" width="330" height="106" data-path="images/docs/61ef594d0a96baa53c5d0eebb714b1c823dfe2bd31233fa8be75f6a98d1dc79e-Screenshot_2024-09-09_at_16.34.14.png" />
</Frame>

这将把操作添加到您的应用程序中，并在应用程序运行时初始化 OneSignal SDK：

<Frame>
  <img src="https://mintcdn.com/onesignal/0qspEXXeJ8zJbkJ-/images/docs/88c1ee61db6558d018470de2af99705b96b0fc65fe712bcca4e5de552db10aa7-Screenshot_2024-09-09_at_16.34.59.png?fit=max&auto=format&n=0qspEXXeJ8zJbkJ-&q=85&s=4b15b27f21ca97473009b36b8988824b" width="391" height="63" data-path="images/docs/88c1ee61db6558d018470de2af99705b96b0fc65fe712bcca4e5de552db10aa7-Screenshot_2024-09-09_at_16.34.59.png" />
</Frame>

### 2. 导出项目

<Tabs>
  <Tab title="APK 下载（仅 Android）">
    打开开发者菜单并下载 APK：

    <Frame>
      <img src="https://mintcdn.com/onesignal/_KaXe4GQkxsEfa17/images/docs/3df0cad35728b0e828b3465cd3e46556336e35af2afaf646ed2718c33cb10eff-Screenshot_2024-09-16_at_10.38.32.png?fit=max&auto=format&n=_KaXe4GQkxsEfa17&q=85&s=555bc4c195596f26147ed6eb23caedb3" width="910" height="810" data-path="images/docs/3df0cad35728b0e828b3465cd3e46556336e35af2afaf646ed2718c33cb10eff-Screenshot_2024-09-16_at_10.38.32.png" />
    </Frame>

    APK 下载完成后，您可以通过将 APK 拖入 Android 模拟器来安装并测试应用程序。推送功能应该立即工作，您可以在通过原生提示提供推送权限后立即向设备发送推送通知。
  </Tab>

  <Tab title="完整项目下载（iOS 和 Android）">
    打开开发者菜单并下载项目代码：

    <Frame>
      <img src="https://mintcdn.com/onesignal/_KaXe4GQkxsEfa17/images/docs/3a262e0407e7a9d37b5ee7fafeb4eef52432b4152973ac4964493d2f1be0c472-Screenshot_2024-09-16_at_10.47.18.png?fit=max&auto=format&n=_KaXe4GQkxsEfa17&q=85&s=6145a1a5780183a4e8a96ba9f194d269" width="856" height="798" data-path="images/docs/3a262e0407e7a9d37b5ee7fafeb4eef52432b4152973ac4964493d2f1be0c472-Screenshot_2024-09-16_at_10.47.18.png" />
    </Frame>
  </Tab>
</Tabs>

### 3. iOS 设置

下载的项目可能不会立即可以在 iOS 中启动。在设置 OneSignal 特定附加功能之前，您需要确保项目已完全构建。操作如下：

* 打开终端窗口，cd（更改目录）到下载项目的 `ios` 文件夹。
* 在终端中输入 `flutter build ios` 并按 Enter 键。等待构建完成，这可能需要一些时间，具体取决于您项目的大小。
* 仍在终端中输入 `pod install` 并按 Enter 键。等待 pod 安装完成。

在 Xcode 中打开位于您项目 ios 文件夹中的 `.xcworkspace` 文件。

选择**根项目 > 您的主应用程序目标 > 签名和功能**。

如果您没有看到推送通知已启用，请单击 **+ Capability** 并添加**推送通知**。确保为您的团队和 Bundle Identifier 输入正确的详细信息。

<Frame>
  <img src="https://mintcdn.com/onesignal/0qspEXXeJ8zJbkJ-/images/docs/82b4cec-1.png?fit=max&auto=format&n=0qspEXXeJ8zJbkJ-&q=85&s=d21289daf4e3311536bfc364d7527f7d" width="2284" height="1120" data-path="images/docs/82b4cec-1.png" />
</Frame>

再次单击 **+ Capability** 并添加**后台模式**。然后勾选**远程通知**。

<Frame>
  <img src="https://mintcdn.com/onesignal/3zq1PvSaqvUE2bIx/images/docs/2269f7e-2.png?fit=max&auto=format&n=3zq1PvSaqvUE2bIx&q=85&s=976c5bc914e9a89da5cd8bbc49bf6cca" width="2300" height="1306" data-path="images/docs/2269f7e-2.png" />
</Frame>

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

OneSignalNotificationServiceExtension 允许您的 iOS 应用程序接收包含图像、按钮和徽章的丰富通知。OneSignal 的确认交付分析功能也需要它。

在 Xcode 中选择 **文件 > 新建 > 目标...**

选择**通知服务扩展**，然后单击**下一步**。

<Frame>
  <img src="https://mintcdn.com/onesignal/MUgio66t0sYhGEvj/images/docs/6eb36bd-73ca2a9-1.png?fit=max&auto=format&n=MUgio66t0sYhGEvj&q=85&s=e00c22fe2866135fdfd3267b63e2b580" width="1470" height="1052" data-path="images/docs/6eb36bd-73ca2a9-1.png" />
</Frame>

输入产品名称为 `OneSignalNotificationServiceExtension` 并按**完成**。

<Frame>
  <img src="https://mintcdn.com/onesignal/0qspEXXeJ8zJbkJ-/images/docs/854f36b-Screenshot_2023-12-26_at_9.19.02_PM.png?fit=max&auto=format&n=0qspEXXeJ8zJbkJ-&q=85&s=b622e02e68381234bed7a87668a17b81" width="1314" height="937" data-path="images/docs/854f36b-Screenshot_2023-12-26_at_9.19.02_PM.png" />
</Frame>

不要在选择**完成**后显示的对话框中激活方案。

在“激活方案”提示上按**取消**。

<Frame caption="通过取消，您可以继续调试您的应用程序，而不是刚创建的扩展。如果您意外激活了，您可以在设备选择器附近的中上部切换回调试您的应用程序目标。">
  <img src="https://mintcdn.com/onesignal/9_Q1FZLh6C0BFLq-/images/docs/c59226d-d8186b6-300.png?fit=max&auto=format&n=9_Q1FZLh6C0BFLq-&q=85&s=26f4fd19ea850cbb252cb5bbbbc70b06" width="300" height="420" data-path="images/docs/c59226d-d8186b6-300.png" />
</Frame>

选择 **OneSignalNotificationServiceExtension** 目标和**通用**设置。

将**最低部署版本**设置为与**您的主应用程序目标相同的值**。这应该是 iOS 11 或更高版本。

<Frame caption="这应该与您的主应用程序目标的值相同。">
  <img src="https://mintcdn.com/onesignal/56ctKxZSV4m5VEkn/images/docs/b9ac509-flutter-mindeployment.png?fit=max&auto=format&n=56ctKxZSV4m5VEkn&q=85&s=923c5bf3f264ad5e3847558ece7c9a13" width="2290" height="1058" data-path="images/docs/b9ac509-flutter-mindeployment.png" />
</Frame>

#### 添加 App Groups

App Groups 允许您的应用程序和 OneSignalNotificationServiceExtension 在收到通知时进行通信，即使您的应用程序未处于活动状态。这对于徽章和确认交付是必需的。

选择您的**主应用程序目标 > 签名和功能 > + Capability > App Groups**。

<Frame>
  <img src="https://mintcdn.com/onesignal/9_Q1FZLh6C0BFLq-/images/docs/ca64b5e-flutter-appgroups1.png?fit=max&auto=format&n=9_Q1FZLh6C0BFLq-&q=85&s=04e88b94d3d6b8382342520cf794b027" width="2288" height="1176" data-path="images/docs/ca64b5e-flutter-appgroups1.png" />
</Frame>

在 **App Groups** 中，单击 **+** 按钮。

将 App Groups 容器设置为 `group.YOUR_BUNDLE_IDENTIFIER.onesignal`，其中 `YOUR_BUNDLE_IDENTIFIER` 与您的主应用程序“Bundle Identifier”相同。

<Frame>
  <img src="https://mintcdn.com/onesignal/RWtLFPeffHrC81wI/images/docs/a51bc81-flutter-appgroups2.png?fit=max&auto=format&n=RWtLFPeffHrC81wI&q=85&s=3918fcab2795fc92ade9da8d48afafb5" width="2284" height="1228" data-path="images/docs/a51bc81-flutter-appgroups2.png" />
</Frame>

按 **OK** 并对 OneSignalNotificationServiceExtension 目标重复。

选择 **OneSignalNotificationServiceExtension 目标 > 签名和功能 > + Capability > App Groups**。

<Frame>
  <img src="https://mintcdn.com/onesignal/tc0EvmtSSX56SX0c/images/docs/98c0fa6-flutter-appgroups3.png?fit=max&auto=format&n=tc0EvmtSSX56SX0c&q=85&s=a90bf7c7d8c4c4e883b6a1259ab334af" width="2258" height="1272" data-path="images/docs/98c0fa6-flutter-appgroups3.png" />
</Frame>

在 **App Groups** 中，单击 **+** 按钮。

将 App Groups 容器设置为 `group.YOUR_BUNDLE_IDENTIFIER.onesignal`，其中 `YOUR_BUNDLE_IDENTIFIER` 与\*\*您的主应用程序“Bundle Identifier”\*\*相同。

**不要包含** `OneSignalNotificationServiceExtension`。

<Frame caption="不要包含 OneSignalNotificationServiceExtension">
  <img src="https://mintcdn.com/onesignal/3zq1PvSaqvUE2bIx/images/docs/273e481-flutter-appgroups4.png?fit=max&auto=format&n=3zq1PvSaqvUE2bIx&q=85&s=39f0adff48bce5de08f5f86782a2fdc2" width="2276" height="1238" data-path="images/docs/273e481-flutter-appgroups4.png" />
</Frame>

<Accordion title="Optional instructions to setup custom App Group Name">
  只有在您**不**想使用默认应用组名称（即 `group.{your_bundle_id}.onesignal`）时才需要此步骤。

  打开您的 `Info.plist` 文件并添加一个新的 `OneSignal_app_groups_key` 作为 `String` 类型。

  输入您在上一步中检查的组名称作为其值。

  确保在 `OneSignalNotificationServiceExtension` 文件夹下的 `Info.plist` 中也做同样的操作。
</Accordion>

#### 将 OneSignal SDK 添加到 OneSignalNotificationServiceExtension

更新您的 `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>

在您的 `Podfile` 顶部确保您有 `platform :ios, '11.0'`。- 或者如果您的应用程序需要，则使用更新的 iOS 版本。

<CodeGroup>
  ```Text Podfile theme={null}
  # Uncomment this line to define a global platform for your project
  platform :ios, '11.0'
  ```
</CodeGroup>

打开终端，`cd` 到 `ios` 目录，然后运行 `pod install`。

如果您看到下面的错误，请在您的 podfile 顶部添加 `use_frameworks!` 并再试一次。

```
- Runner (true) and OneSignalNotificationServiceExtension (false) do not both set use_frameworks!.
```

#### OneSignalNotificationServiceExtension 代码

在 Xcode 项目导航器中，选择 **OneSignalNotificationServiceExtension 文件夹**并打开 `NotificationService.m` 或 `NotificationService.swift` 文件。

用以下代码替换整个文件的内容。

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

  import OneSignalExtension

  class NotificationService: UNNotificationServiceExtension {

      var contentHandler: ((UNNotificationContent) -> Void)?
      var receivedRequest: UNNotificationRequest!
      var bestAttemptContent: UNMutableNotificationContent?

      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
                            Note, this extension only runs when mutable-content is set
                            Setting an attachment or action buttons automatically adds this */
              // print("Running NotificationServiceExtension")
              // bestAttemptContent.body = "[Modified] " + bestAttemptContent.body

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

      override func serviceExtensionTimeWillExpire() {
          // Called just before the extension will be terminated by the system.
          // 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)
          }
      }
  }
  ```

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

  - (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
                    Note, this extension only runs when mutable-content is set
                    Setting an attachment or action buttons automatically adds this */
      // NSLog(@"Running NotificationServiceExtension");
      // self.bestAttemptContent.body = [@"[Modified] " stringByAppendingString:self.bestAttemptContent.body];

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

  - (void)serviceExtensionTimeWillExpire {
      // Called just before the extension will be terminated by the system.
      // 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>

<Frame caption="NotificationService.swift 文件的示例。">
  <img src="https://mintcdn.com/onesignal/YOTSrtBSoqdrJ37A/images/docs/4329841-Image_12-26-23_at_9.50_PM.jpg?fit=max&auto=format&n=YOTSrtBSoqdrJ37A&q=85&s=8d397d1cc8ee523f1372d0146b3a495e" width="2126" height="1104" data-path="images/docs/4329841-Image_12-26-23_at_9.50_PM.jpg" />
</Frame>

***

## 测试 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>

***

***
