通知服务扩展允许您在向用户显示推送通知之前拦截和修改推送通知。
Android 通知服务扩展
允许您在向用户显示通知之前处理通知。常见用例包括:
在后台接收数据,可以显示或不显示通知。
根据客户端应用逻辑覆盖特定通知设置,例如自定义强调色、振动模式或任何其他可用的 NotificationCompat 选项。
有关更多详细信息,请参阅 Android 关于 NotificationCompat 选项的文档 。
第 1 步:为服务扩展创建一个类
创建一个扩展 INotificationServiceExtension 的类并实现 onNotificationReceived 方法。
方法 onNotificationReceived 参数是 event,类型为 INotificationReceivedEvent 。
package your. package .name
import androidx.annotation. K eep;
import com.onesignal.notifications.IActionButton;
import com.onesignal.notifications.IDisplayableMutableNotification;
import com.onesignal.notifications.INotificationReceivedEvent;
import com.onesignal.notifications.INotificationServiceExtension;
@ Keep // Keep is required to prevent minification from renaming or removing your class
public class NotificationServiceExtension implements INotificationServiceExtension {
@ Override
public void onNotificationReceived ( INotificationReceivedEvent event ) {
IDisplayableMutableNotification notification = event . getNotification ();
if ( notification . getActionButtons () != null ) {
for ( IActionButton button : notification . getActionButtons ()) {
// you can modify your action buttons here
}
}
/* Add customizations here. See examples below for additional methods to modify the notification*/
}
}
@Keep 注解可防止 ProGuard/R8 在代码压缩期间重命名或移除您的类。
第 2 步:自定义通知
以下是您可以在上述模板通知服务扩展类中实现的常见示例。
调用 event.preventDefault() 可以阻止通知自动显示,然后决定是手动显示还是完全不显示。 event . preventDefault ();
//执行一些异步工作,然后决定显示或关闭
new Thread (() -> {
try {
Thread . sleep ( 1000 );
} catch ( InterruptedException ignored ) {}
//手动显示通知
event . getNotification (). display ();
}). start ();
调用 event.preventDefault() 后,如果您从未调用 display(),通知将被静默丢弃,不会有任何提示。详情请参阅重复通知 。 String promoCode = notification . getAdditionalData () != null
? notification . getAdditionalData (). optString ( "promo_code" , null )
: null ;
if (promoCode != null ) {
String updatedBody = notification . getBody () + " Use code: " + promoCode;
notification . setExtender (builder -> {
builder . setContentText (updatedBody);
});
}
int iconResId = R . drawable . icon_default ;
String type = notitifcation . getAdditionalData () != null
? notification . getAdditionalData (). optString ( "type" , "" )
: "" ;
switch (type) {
case "sale" :
iconResId = R . drawable . icon_sale ;
break ;
case "reminder" :
iconResId = R . drawable . icon_reminder ;
break ;
}
int finalIconResId = iconResId;
notification . setExtender (builder -> {
builder . setColor ( 0xFF0000FF ). setSmallIcon (finalIconResId);
});
此处引用的图标必须存在于应用的 res/drawable 目录中。
第 3 步:将服务扩展添加到您的 AndroidManifest.xml
在 AndroidManifest.xml 文件的 application 标签中添加类名和值作为 meta-data。忽略任何”未使用”警告。
< application >
< meta-data
android:name = "com.onesignal.NotificationServiceExtension"
android:value = "com.onesignal.example.NotificationServiceExtension" />
</ application >
将 com.onesignal.example.NotificationServiceExtension 替换为您的类的完全限定名称。
iOS 通知服务扩展
UNNotificationServiceExtension 允许您在向用户显示推送通知之前修改推送通知的内容,并且是其他重要功能所必需的,例如:
如果您遵循了我们针对您的应用的移动 SDK 设置 说明,扩展应该已经配置好了。本节将说明如何访问 OneSignal 通知有效负载数据并解决您可能遇到的任何问题。
获取 iOS 推送载荷
didReceive(_:withContentHandler:) 的重写会调用 OneSignalExtension.didReceiveNotificationExtensionRequest。在调用该方法之前,您可以读取或修改 bestAttemptContent。
在此示例中,我们发送包含以下数据的通知:
{
"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" ]
}
通过 userInfo 的 custom 字典中的 a 键,在 OneSignalNotificationServiceExtension 中访问此附加 data:
if let bestAttemptContent = bestAttemptContent {
if let customData = bestAttemptContent.userInfo[ "custom" ] as? [ String : Any ],
let additionalData = customData[ "a" ] as? [ String : Any ] {
if let jsonData = try ? JSONSerialization. data ( withJSONObject : additionalData, options : . prettyPrinted ),
let jsonString = String ( data : jsonData, encoding : . utf8 ) {
print ( "The additionalData dictionary in JSON format: \n \( jsonString ) " )
} else {
print ( "Failed to convert additionalData to JSON format." )
}
}
if let messageData = bestAttemptContent.userInfo[ "aps" ] as? [ String : Any ],
let apsData = messageData[ "alert" ] as? [ String : Any ],
let body = apsData[ "body" ] as? String ,
let title = apsData[ "title" ] as? String {
print ( "The message contents is: \( body ) , message headings is: \( title ) " )
} else {
print ( "Unable to retrieve apsData" )
}
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 is: The message contents, message headings is: The message title
iOS 通知服务扩展故障排除
本指南用于调试 iOS 移动应用上未显示图片、操作按钮或确认送达的问题。
检查您的 Xcode 设置
在 General > Targets 中确保您的主应用目标 和 OneSignalNotificationServiceExtension 目标具有相同且正确的:
Supported Destinations (支持的目标)
Minimum Deployment (最低部署版本,iOS 14.5 或更高版本)
如果您使用的是 Cocoapods,请确保这些与 Podfile 中的主目标匹配,以避免构建错误。
继续在 OneSignalNotificationServiceExtension > Info 标签中,展开 NSExtension 键。确保您看到:
< 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。
关闭”Copy only when installing”(仅在安装时复制)
选择您的主应用目标 > Build Phases > Embed App Extensions 。确保”Copy only when installing”(仅在安装时复制)未选中。如果已选中,请取消选中:
调试 iOS 通知服务扩展
按照以下步骤验证通知服务扩展是否正确设置。
1. 更新 OneSignalNotificationServiceExtension 代码
打开 NotificationService.m 或 NotificationService.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 : "YOUR_BUNDLE_ID" , category : "OneSignalNotificationServiceExtension" ), type : OSLogType. debug , userInfo. debugDescription )
if let bestAttemptContent = bestAttemptContent {
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)
}
}
}
调试日志类型需要在控制台中通过 Action > Include Debug Messages 启用。
2. 更改活动方案
将您的活动方案设置为 OneSignalNotificationServiceExtension。
3. 构建并运行项目
在 Xcode 中在真实设备上构建并运行项目。
4. 打开控制台
在 Xcode 中,选择 Window > Devices and Simulators 。
您应该会看到您的设备已连接。选择 Open Console (打开控制台)。
5. 检查控制台
在控制台中:
选择 Action > Include Debug Messages (操作 > 包含调试消息)
搜索 OneSignalNotificationServiceExtension 作为 CATEGORY(类别)
选择 Start (开始)
向此设备发送一条带有消息的通知(如果从推送通知 API 发送,请使用 contents 属性)。在此示例中,载荷为:
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,并再次按照移动 SDK 设置 进行操作,以验证集成是否正确。
常见问题
为什么我的通知服务扩展在 iOS 上无法运行?
扩展仅在通知设置了 mutable-content 时才会运行。OneSignal 会自动为包含附件或操作按钮的通知设置此项。请验证您的 Xcode 设置是否与故障排除部分 中的要求一致。
我可以在 Android 上阻止通知显示吗?
可以,调用 event.preventDefault() 可以阻止通知显示。之后可以调用 event.getNotification().display() 手动显示,或者不调用以静默丢弃通知。详情请参阅重复通知 。
Android 上是否需要 @Keep 注解?
是的,@Keep 注解可防止 ProGuard/R8 在代码压缩期间重命名或移除实现了 INotificationServiceExtension 的类。
相关页面
移动 SDK 设置 为 iOS 和 Android 安装和配置 OneSignal SDK。