描述
由于华为从 2023 年 9 月开始,限制本地通知弹出频次,导致 IMKit 直接调用系统接口发送的本地通知无法弹出。具体表现为华为设备上 IMKit 无法正常弹出本地通知。
应用程序自行弹出的本地通知也会受到同样的限制。
分析(根因分析、需求分析)
华为从 2023 年 9 月开始,类似对远程推送通知的限制,华为设备上将基于《华为消息分类标准》对应用发送本地通知进行分类管理,并对资讯营销消息统一进行频次管控,这将造成直接调用系统接口发送的通知受到限制,甚至无法弹出。
以下为华为官网公告节选:
- 2023年2月28日发布:《华为消息分类调整通知》
- 2023年7月21日发布:《本地通知频次及分类管控通知》
为了给用户提供更好的消息通知体验,预计2023年9月开始,应用发送的本地资讯营销消息将计入总的资讯营销消息频次数量,每天应用的推送频次有总量限制,具体请参见《推送数量管理细则》。
应用可通过申请自分类权益,对本地通知进行分类管理(应用若已申请云端相关消息类型,将自动生效对应的本地通知类型,本地通知无需重复申请,但应用仍需适配开发)。
IMKit 在调用系统 API 创建 Notification 时,并未设置默认的 Category 属性。如果您已申请华为的自分类权益,您需要在 IMKit 创建 Notification 时设置有效的 Category 属性。
IMKit 5.x 的适配方案
以下方案仅适用于 IMKit < 5.6.4 的项目,您任选其一即可。如果 IMKit >= 5.6.4,无需使用以下方案适配。
建议升级至 5.6.4 及之后版本。IMKit 从 5.6.4 版本开始,内部弹出本地通知的
category
默认设置为CATEGORY_MESSAGE
,应用程序不需要额外调用 API 进行设置。
由应用程序完全接管本地通知
本方案完全拦截了 IMKit 内部创建的本地通知,由应用程序接管后自行弹出本地通知,应用程序在创建本地通知时设置可以有效的 Category 属性。该方案适用于对本地通知有较高自定义需求已经对 IMKit 创建本地通知进行自定义的项目。
注意:采用该方案,应用程序需要自行处理前后台判断、是否响铃、是否震动等行为。如需帮助,您可以参考 IMKit 内部创建本地通知时的处理方案,参见【复用 IMKit 弹出本地通知的代码】 方案中
RongNotificationManager
类中的代码。
IMKit 5.X 支持对内部创建的本地通知进行拦截。应用程序可以设置拦截器,在 IMKit 弹出内部创建的本地通知前拦截,由应用程序接管本地通知的逻辑。
@Override
public boolean isNotificationIntercepted(Message message) {
...
return true; //true, 拦截本地通知,SDK 不再处理本地通知的逻辑。
}
应用程序接管本地通知弹出的逻辑后,在应用调用系统 API 创建通知的代码下方,增加以下判断语句,设置您申请的华为自定义分类,以设置为 Notification.CATEGORY_MESSAGE
为例。
<!-- 在 Notification.Builder builder = new Notification.Builder(context); 下方,增加以下判断语句:-->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
builder.setCategory(Notification.CATEGORY_MESSAGE);
}
具体为下图位置
复用 IMKit 5.X 弹出本地通知的代码
本方案需要在 App 项目中复用了 IMKit 内部创建本地通知的代码,适用于通过 Maven、本地 Module、源码集成 IMKit 的项目。注意,后续您可能需要在 IMKit 升级时维护该代码。
该方案要求将 IMKit 创建本地通知的代码复制到您的工程中,修改其中创建本地通知的方法,并添加设置 Category 属性的逻辑。接着,您需要拦截 IMKit 内部创建的本地通知,控制 IMKit 使用您修改后的逻辑弹出本地通知。
-
全局搜索这以下两个类。复制两个类的全部内容,在您的项目目录下创建对应文件(假设创建同名文件):
- RongNotificationManager
- NotificationUtil
-
打开您项目目录下
NotificationUtil.java
文件,修改创建通知的createNotification
方法:// 找到 createNotification 方法中的这一行 Notification.Builder builder = new Notification.Builder(context); // 添加以下判断语句即可,此处设置您申请的华为自定义分类,以Notification.CATEGORY_MESSAGE 为例 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { builder.setCategory(Notification.CATEGORY_MESSAGE); }
具体为下图位置
-
初始化您项目中
RongNotificationManager
类,拦截 SDK 内部创建的本地通知,改为使用项目中的方法弹出本地通知。// import <project/path/to/RongNotificationManager/>; 导入您项目中的 RongNotificationManager 类 RongNotificationManager.getInstance().init(this); // 调用 IMKit 的方法拦截 SDK 内部创建的本地通知 RongConfigCenter.notificationConfig().setInterceptor(new DefaultInterceptor() { @Override public boolean isNotificationIntercepted(Message message) { // 此处调用您项目中的 RongNotificationManager 类的 preToNotify 方法 RongNotificationManager.getInstance().preToNotify(message); // `true` 表示拦截,拦截后 SDK 不再继续执行弹出本地通知的逻辑 return true; } });
直接修改 IMKit 5.X 源码
仅适用于使用源码集成 IMKit 的客户。直接修源码可能会延长融云为您解决问题的时长,非特殊情况不建议您直接修改 IMKit 源码。
-
全局搜索这个类:
- NotificationUtil
-
打开
NotificationUtil.java
文件,修改创建通知的createNotification
方法即可:// 找到 createNotification 方法中的这一行 Notification.Builder builder = new Notification.Builder(context); // 添加以下判断语句即可,此处设置您申请的华为自定义分类,以Notification.CATEGORY_MESSAGE 为例 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { builder.setCategory(Notification.CATEGORY_MESSAGE); }
具体为下图位置
IMKit 4.x 的适配方案
已自定义修改 IMKit 4.X 本地通知
您的现有项目可能拦截了 IMKit 内部创建的本地通知,接管了本地通知弹出的逻辑。由应用程序接管后自行弹出本地通知。
您只需要在项目中调用系统 API 创建通知的代码下方,增加以下判断语句,设置您已申请的华为自定义分类,以设置为 Notification.CATEGORY_MESSAGE
为例。
<!-- 在 Notification.Builder builder = new Notification.Builder(context); 下方,增加以下判断语句:-->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
builder.setCategory(Notification.CATEGORY_MESSAGE);
}
复用 IMKit 4.X 弹出本地通知的代码
本方案需要在 App 项目中复用了 IMKit 内部创建本地通知的代码,适用于通过 Maven、本地 Module、源码集成 IMKit 的项目。注意,后续您可能需要在 IMKit 升级时维护该代码。
该方案要求将 IMKit 创建本地通知的代码复制到您的工程中,修改其中创建本地通知的方法,并添加设置 Category 属性的逻辑。接着,您需要拦截 IMKit 内部创建的本地通知,控制 IMKit 使用您修改后的逻辑弹出本地通知。
如果在您的现有项目中,应用程序已经主动拦截了 IMKit 本地通知,并由应用程序自行弹出通知,您可以参考 【客户端已自定义本地通知的适配方案】。
-
全局搜索这个类。复制这个类的全部内容,在您的项目目录下创建对应文件(假设创建同名文件):
- RongNotificationInterface
-
打开您项目目录下
RongNotificationInterface.java
文件,修改创建通知的createNotification
方法:// 找到 createNotification 方法中的这一行 Notification.Builder builder = new Notification.Builder(context); // 添加以下判断语句即可,此处设置您申请的华为自定义分类,以Notification.CATEGORY_MESSAGE 为例 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { builder.setCategory(Notification.CATEGORY_MESSAGE); }
具体为下图位置
-
自定义
PushMessageReceiver
,继承自融云的PushMessageReceiver
实现onNotificationMessageArrived
方法并 return true ,调用您项目目录下RongNotificationInterface
的 sendNotification 方法import io.rong.push.notification.PushMessageReceiver; //继承自融云的PushMessageReceiver import io.rong.push.notification.PushNotificationMessage; public class CustomPushMessageReceiver extends PushMessageReceiver { // 此处为内部创建的本地通知 @Override public boolean onNotificationMessageArrived(Context context, PushType pushType, PushNotificationMessage pushNotificationMessage) { // 此处调用您项目中的 RongNotificationInterface 类的 sendNotification 方法 RongNotificationInterface.sendNotification(context,pushNotificationMessage); // `true` 表示拦截,拦截后 SDK 不再继续执行弹出本地通知的逻辑 return true; } @Override public boolean onNotificationMessageClicked(Context context, PushType pushType, PushNotificationMessage pushNotificationMessage) { return false; } }
-
在您的
AndroidManifest.xml
中注册自定义的PushMessageReceiver
<receiver android:name="CustomPushMessageReceiver" android:exported="true"> <intent-filter> <action android:name="io.rong.push.intent.MESSAGE_ARRIVED" /> <action android:name="io.rong.push.intent.MESSAGE_CLICKED" /> <action android:name="io.rong.push.intent.THIRD_PARTY_PUSH_STATE" /> </intent-filter> </receiver>
直接修改 IMKit 4.X 源码
仅适用于使用源码集成 IMKit 的客户。直接修源码可能会延长融云为您解决问题的时长,非特殊情况不建议您直接修改 IMKit 源码。
-
打开
RongNotificationInterface.java
文件,修改创建通知的createNotification
方法即可:// 找到 createNotification 方法中的这一行 Notification.Builder builder = new Notification.Builder(context); // 添加以下判断语句即可,此处设置您申请的华为自定义分类,以Notification.CATEGORY_MESSAGE 为例 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { builder.setCategory(Notification.CATEGORY_MESSAGE); }
具体为下图位置
链接
更多支持
如有疑问,欢迎提交工单