跳转到主要内容

概述

通知服务扩展允许您在向用户显示推送通知之前拦截和修改推送通知。这使得以下功能成为可能:
  • 后台数据处理
  • 自定义样式(颜色、图标、振动)
  • 富媒体附件(图像、视频)
  • 确认递送/分析
  • 操作按钮选项
您可以通过 OSNotification 类 访问从 OneSignal 发送的推送通知中的数据

Android 通知服务扩展

允许您在向用户显示通知之前处理通知。常见用例包括:
  • 在后台接收数据,可以显示或不显示通知。
  • 根据客户端应用逻辑覆盖特定的通知设置,例如自定义强调色、振动模式或任何其他可用的 NotificationCompat 选项。
有关更多详细信息,请参阅 Android 关于 NotificationCompat 选项的文档。

1. 为服务扩展创建一个类

创建一个扩展 INotificationServiceExtension 的类并实现 onNotificationReceived 方法。 onNotificationReceived 方法参数是类型为 INotificationReceivedEventevent
package your.package.name

import androidx.annotation.Keep;
import com.onesignal.notifications.IActionButton;
import com.onesignal.notifications.IDisplayableMutableNotification;
import com.onesignal.notifications.INotificationReceivedEvent;
import com.onesignal.notifications.INotificationServiceExtension;

@Keep // 需要 Keep 来防止混淆器重命名或删除您的类
public class NotificationServiceExtension implements INotificationServiceExtension {

   @Override
   public void onNotificationReceived(INotificationReceivedEvent event) {
      IDisplayableMutableNotification notification = event.getNotification();

      if (notification.getActionButtons() != null) {
         for (IActionButton button : notification.getActionButtons()) {
            // 您可以在此处修改您的操作按钮
         }
      }

   /* 在此处添加自定义项。请参阅下面的示例,了解更多修改通知的方法 */
   }
}

2. 示例用例

以下是您可以在上述模板通知服务扩展类中实现的常见示例。
  • 阻止通知显示
  • 添加自定义字段
  • 更改通知颜色和图标
event.preventDefault();

//执行一些异步工作,然后决定是显示还是关闭
new Thread(() -> {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException ignored) {}

    //手动显示通知
    event.getNotification().display();
}).start();

3. 将服务扩展添加到您的 AndroidManifest.xml

在应用程序标签内的 AndroidManifest.xml 文件中添加类名和值作为 meta-data。忽略任何”未使用”的警告。
XML
<application> 
  <!-- 保持 android:name 如所示,将 android:value 设置为您的类全限定名称-->
  <meta-data 
    android:name="com.onesignal.NotificationServiceExtension"
    android:value="com.onesignal.example.NotificationServiceExtension" />
</application>

iOS 通知服务扩展

UNNotificationServiceExtension 允许您在向用户显示推送通知之前修改推送通知的内容,并且对于以下其他重要功能是必需的: 如果您已经按照我们的移动 SDK 设置说明为您的应用配置了这项功能,那么您可能已经设置过了,但本节将解释如何访问 OneSignal 通知载荷数据并解决您可能遇到的任何问题。

获取 iOS 推送载荷

当按照移动 SDK 设置进行操作时,您会找到向 OneSignalNotificationServiceExtension 添加代码的部分。 在该代码中,有一个方法 OneSignalExtension.didReceiveNotificationExtensionRequest。这是我们在向用户显示通知之前将通知的 bestAttemptContent 传递给应用的地方。在调用此方法之前,您可以获取通知载荷并(如果需要)在向用户显示之前更新它。 在此示例中,我们发送一个包含以下数据的通知:
JSON
{
  "app_id": "YOUR_APP_ID",
  "target_channel": "push",
  "headings": {"en": "The message title"},
  "contents": {"en": "The message contents"},
  "data":{
    "additional_data_key_1":"value_1",
    "additional_data_key_2":"value_2"
    },
  "include_subscription_ids": ["SUBSCRIPTION_ID_1"]
}
我们可以在 OneSignalNotificationServiceExtension 中通过使用 a 参数的 custom 对象访问这些附加的 data
// 检查 `bestAttemptContent` 是否存在
if let bestAttemptContent = bestAttemptContent {

    // 尝试从通知载荷中检索 "custom" 数据
    if let customData = bestAttemptContent.userInfo["custom"] as? [String: Any],
       let additionalData = customData["a"] as? [String: Any] {

        // 将 `additionalData` 字典转换为 JSON 字符串以便记录
        if let jsonData = try? JSONSerialization.data(withJSONObject: additionalData, options: .prettyPrinted),
           let jsonString = String(data: jsonData, encoding: .utf8) {
            // 成功转换为 JSON;记录格式化的 JSON 字符串
            print("The additionalData dictionary in JSON format:\n\(jsonString)")
        } else {
            // 无法将 `additionalData` 字典转换为 JSON
            print("无法将 additionalData 转换为 JSON 格式。")
        }
    }

    // 尝试从通知载荷中检索 "aps" 数据
    if let messageData = bestAttemptContent.userInfo["aps"] as? [String: Any],
       let apsData = messageData["alert"] as? [String: Any],
       let body = apsData["body"] as? String,  // 提取警报的 "body"
       let title = apsData["title"] as? String {  // 提取警报的 "title"
        // 成功检索到 body 和 title;记录值
        print("消息内容是:\(body),消息标题是:\(title)")
    } else {
        // 无法检索 "aps" 数据或其内容
        print("无法检索 apsData")
    }

    // 将通知传递给 OneSignal 进行进一步处理
    OneSignalExtension.didReceiveNotificationExtensionRequest(self.receivedRequest,
                                                              with: bestAttemptContent,
                                                              withContentHandler: self.contentHandler)
}
示例控制台输出:
The additionalData dictionary in JSON format:
{
  "additional_data_key_1" : "value_1",
  "additional_data_key_2" : "value_2"
}
消息内容是:The message contents,消息标题是:The message title

iOS 通知服务扩展故障排除

本指南用于调试 iOS 移动应用上图像、操作按钮或确认递送不显示的问题。 检查您的 Xcode 设置 General > Targets 中,确保您的主应用目标和 OneSignalNotificationServiceExtension 目标具有相同且正确的”Supported Destinations”,并且您的”Minimum Deployment”设置为 iOS 14.5 或更高版本。 如果您使用 Cocoapods,请确保这些与 Podfile 中的主目标匹配,以避免构建错误。

在 Xcode 中配置通知服务扩展

示例显示 OneSignalNotificationServiceExtension 目标与 iOS 14 具有相同的最低部署要求

OneSignalNotificationServiceExtension > Info 选项卡中继续,展开 NSExtension 键。确保您能看到:

示例显示查看 Info 选项卡而非 XML

XML 示例:
XML
 <dict>
   <key>NSExtensionPointIdentifier</key>
   <string>com.apple.usernotifications.service</string>
   <key>NSExtensionPrincipalClass</key>
   <string>$(PRODUCT_MODULE_NAME).NotificationService</string>
 </dict>
如果使用 Objective-C,请使用 NotificationService 而不是 $(PRODUCT_MODULE_NAME).NotificationService
关闭”仅在安装时复制” 选择您的 主应用目标 > 构建阶段 > 嵌入应用扩展。确保未选中”仅在安装时复制”。如果已选中,请取消选中:

嵌入应用扩展构建阶段设置

如何调试通知服务扩展不运行的问题

1. 更新 OneSignalNotificationServiceExtension 代码

打开 NotificationService.mNotificationService.swift 并用以下代码替换整个文件内容。(代码与我们原始的设置代码相同,只是添加了一些额外的日志记录。 确保将 YOUR_BUNDLE_ID 替换为您的实际 Bundle ID。
import UserNotifications
import OneSignalExtension
import os.log

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)

        let userInfo = request.content.userInfo
        let custom = userInfo["custom"]
        print("Running NotificationServiceExtension: userInfo = \(userInfo.description)")
        print("Running NotificationServiceExtension: custom = \(custom.debugDescription)")
        //需要在控制台 > 操作 > 包含调试消息中启用调试日志类型
        os_log("%{public}@", log: OSLog(subsystem: "com.onesignal.OneSignal-Swift-Sample", category: "OneSignalNotificationServiceExtension"), type: OSLogType.debug, userInfo.debugDescription)

        if let bestAttemptContent = bestAttemptContent {
            /* 调试:取消注释下面的 2 行来检查此扩展是否正在执行
                          注意,此扩展仅在设置 mutable-content 时运行
                          设置附件或操作按钮会自动添加此项 */
            print("Running NotificationServiceExtension")
            bestAttemptContent.body = "[Modified] " + bestAttemptContent.body

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

    override func serviceExtensionTimeWillExpire() {
        // 在系统即将终止扩展之前调用。
        // 将此作为传递修改内容的“最佳尝试”机会,否则将使用原始推送载荷。
        if let contentHandler = contentHandler, let bestAttemptContent =  bestAttemptContent {
            OneSignalExtension.serviceExtensionTimeWillExpireRequest(self.receivedRequest, with: self.bestAttemptContent)
            contentHandler(bestAttemptContent)
        }
    }

}

2. 更改您的活动方案

将您的活动方案设置为 OneSignalNotificationServiceExtension

Xcode 活动方案选择

3. 构建并运行项目

在 Xcode 中在真实设备上构建并运行项目。

4. 打开控制台

在 Xcode 中,选择 窗口 > 设备和模拟器

Xcode 设备和模拟器窗口

您应该能看到您的设备已连接。选择 打开控制台

设备控制台访问按钮

5. 检查控制台

在控制台中:
  • 选择操作 > 包含调试消息
  • 搜索 OneSignalNotificationServiceExtension 作为类别
  • 选择 开始

控制台调试配置

向此设备发送带有消息的通知(如果从 Create message API 发送,请使用 contents 属性)。在此示例中,载荷为:
cURL
  //替换为您自己的应用数据:
  //YOUR_API_KEY, YOUR_APP_ID, SUBSCRIPTION_ID_1

curl --request POST \
 --url 'https://api.onesignal.com/notifications' \
 --header 'Authorization: Key YOUR_API_KEY' \
 --header 'accept: application/json' \
 --header 'content-type: application/json' \
 --data '
{
"app_id": "YOUR_APP_ID",
"target_channel": "push",
"headings": {"en": "The message title"},
"contents": {"en": "The message contents"},
"data":{"additional_data_key_1":"value_1","additional_data_key_2":"value_2"},
"include_subscription_ids": [
"SUBSCRIPTION_ID_1"
]
}'
您应该能看到在应用运行和未运行时记录的消息。

控制台调试输出示例

如果您没有看到消息,请从您的应用中移除 OneSignal 并再次按照我们的 Mobile SDK Setup 来验证您是否正确设置了 OneSignal。
I