关于华为限制本地通知频次及分类的适配流程

描述

由于华为从 2023 年 9 月开始,限制本地通知弹出频次,导致 IMKit 直接调用系统接口发送的本地通知无法弹出。具体表现为华为设备上 IMKit 无法正常弹出本地通知。

应用程序自行弹出的本地通知也会受到同样的限制。

分析(根因分析、需求分析)

华为从 2023 年 9 月开始,类似对远程推送通知的限制,华为设备上将基于《华为消息分类标准》应用发送本地通知进行分类管理,并对资讯营销消息统一进行频次管控,这将造成直接调用系统接口发送的通知受到限制,甚至无法弹出。

以下为华为官网公告节选:

为了给用户提供更好的消息通知体验,预计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 创建本地通知进行自定义的项目。

:tipping_hand_man: 注意:采用该方案,应用程序需要自行处理前后台判断、是否响铃、是否震动等行为。如需帮助,您可以参考 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 使用您修改后的逻辑弹出本地通知。

  1. 全局搜索这以下两个类。复制两个类的全部内容,在您的项目目录下创建对应文件(假设创建同名文件):

    • RongNotificationManager
    • NotificationUtil

  2. 打开您项目目录下 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);
                  }
    
    

    具体为下图位置

  3. 初始化您项目中 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 源码

:warning: 仅适用于使用源码集成 IMKit 的客户。直接修源码可能会延长融云为您解决问题的时长,非特殊情况不建议您直接修改 IMKit 源码。

  1. 全局搜索这个类:

    • NotificationUtil
  2. 打开 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 使用您修改后的逻辑弹出本地通知。

:tipping_hand_man: 如果在您的现有项目中,应用程序已经主动拦截了 IMKit 本地通知,并由应用程序自行弹出通知,您可以参考 【客户端已自定义本地通知的适配方案】。

  1. 全局搜索这个类。复制这个类的全部内容,在您的项目目录下创建对应文件(假设创建同名文件):

    • RongNotificationInterface

  2. 打开您项目目录下 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);
                  }
    
    

    具体为下图位置

  3. 自定义 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;
        }
    }
    
    
  4. 在您的 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 源码

:warning: 仅适用于使用源码集成 IMKit 的客户。直接修源码可能会延长融云为您解决问题的时长,非特殊情况不建议您直接修改 IMKit 源码。

  1. 打开 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);
                  }
    
    

    具体为下图位置

链接

本地通知频次及分类管控通知

更多支持

如有疑问,欢迎提交工单

1 个赞