在Android8.0以上版本,通知Api发生了很大的变化,当targetSdk升级到26以上的时候,就会碰到不少问题,笔者从接手新项目,一直到今天才发现了一个隐藏很久的bug,点击通知栏,静态注册的广播代码不执行,经过写demo做实验,查阅资料,终于找到了问题所在,欢迎大家看看。
版权声明:本文为xing_star原创文章,转载请注明出处!
对Android 8.0以上版本通知点击无效的一次分析
最近在重构聊天服务,有机会从新梳理下前人写的通知相关的逻辑,隐藏着一个很深的bug,遗留了应该有8个多月了。直到今天才定位出原因,之前一直怀疑是自己设备的问题????????,经过写demo,做实验验证,最终得出结论。
Android 8.0之后通知相关的Api又发生了很大的变化,接手项目的时候,没怎么关注过这块,一直以为没有问题,到今天测试验证,发现还是存在问题的????,问题表象是,点击App通知栏的通知消息,点击之后通知栏还在,一直没有反应(App业务中关于Click通知栏的逻辑没有生效)。抱着对代码怀疑的角度,自己创建了个demo工程,参考Notification的用法,自己做实验观察效果。
实验过程
这里在回顾下自己做实验的过程。
首先创建了个demo工程,添加通知相关的代码,以及动态注册了一个BroadcastReceiver。private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) { if (intent == null || context == null) { return;
}
mNotificationManager.cancel(NOTIFICATION_ID_LIVE);
String type = intent.getStringExtra(PUSH_TYPE); if (PUSH_TYPE_LINK.equals(type)) {
mNumLinkes = 0;
} else if (PUSH_TYPE_LIVE.equals(type)) {
mNumLives = 0;
} //这里可以重新计数 }
};private void registerHeadsetPlugReceiver() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(NOTIFICATION_CLICK_ACTION);
intentFilter.addAction(NOTIFICATION_DELETED_ACTION);
registerReceiver(mBroadcastReceiver, intentFilter);
}private void sendLiveNotification() {
Intent intent = new Intent(NOTIFICATION_CLICK_ACTION); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH);
channel.setBypassDnd(true); //设置绕过免打扰模式
channel.canBypassDnd(); //检测是否绕过免打扰模式
channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);//设置在锁屏界面上显示这条通知
channel.setDescription("测试通知消息内容");
channel.setLightColor(Color.GREEN);
channel.setName("测试通知消息名称");
channel.setShowBadge(true);
channel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
channel.enableVibration(true);
mNotificationManager.createNotificationChannel(channel);
}
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, CHANNEL_ID);
String title = "Push测试";
mBuilder.setContentTitle(title);
mBuilder.setTicker(title);
mBuilder.setContentText("https://233.tv/over140");
mBuilder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
mBuilder.setSmallIcon(R.mipmap.ic_launcher);
mBuilder.setDefaults(Notification.DEFAULT_ALL);
mBuilder.setWhen(System.currentTimeMillis());
mBuilder.setContentIntent(PendingIntent.getBroadcast(this, NOTIFICATION_ID_LIVE, intent, 0));
mBuilder.setDeleteIntent(PendingIntent.getBroadcast(this, NOTIFICATION_ID_LIVE, new Intent(NOTIFICATION_DELETED_ACTION).putExtra(PUSH_TYPE, PUSH_TYPE_LIVE), 0));
mNotificationManager.notify(NOTIFICATION_ID_LIVE, mBuilder.build());
}
第一步的测试代码比较简单,在MainActivity调用sendLiveNotification()方法,就会出现通知栏,之后呢,点击通知栏会发送广播,我们在MainActivity注册了这个广播事件,就能够接收到,看起来没问题。到这里把怀疑点放到了静态注册上,BroadcastReceiver在AndroidManifest.xml中的注册。
接着就是修改代码,把动态注册的代码调整为一个CustomBroadcastReceiver,然后在AndroidManifest.xml中进行注册
android:enabled="true"
android:exported="false">
intent-filter>receiver>public class CustomBroadcastReceiver extends BroadcastReceiver { private int NOTIFICATION_ID_LIVE = 101; private String PUSH_TYPE_LIVE = "PUSH_TYPE_LIVE"; private String PUSH_TYPE = "push_type"; private String PUSH_TYPE_LINK = "PUSH_TYPE_LINK"; private int mNumLinkes; private int mNumLives;
@Override public void onReceive(Context context, Intent intent) {
NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); if (intent == null || context == null) { return;
}
mNotificationManager.cancel(NOTIFICATION_ID_LIVE);
String type = intent.getStringExtra(PUSH_TYPE); if (PUSH_TYPE_LINK.equals(type)) {
mNumLinkes = 0;
} else if (PUSH_TYPE_LIVE.equals(type)) {
mNumLives = 0;
}
}
}
调整完后,继续验证自己的想法。
运行程序,开启debug模式,发现点击通知栏后,在CustomBroadcastReceiver中没有拦截到,到这里就确定了问题肯定是出现在静态注册上面,但是之前的项目中,有些第三方的broadcastReceiver是静态注册,但最终是执行了onReceiver的方法,那肯定是我的使用姿势有问题。于是google搜索了一番,关键词就是android broadcastreceiver androidmanifest android 8.0 不运行,第一篇文章就是我想要找的。参考了一番,发现提到的几个说法值得一试,目前只验证了intent.setPackage(getPackageName());
在查阅资料的过程也特意观察了下log输出07-26 23:30:14.452 1637-1688/? W/BroadcastQueue: Background execution not allowed: receiving Intent { act=me.star.notificationdemo2.click flg=0x10 } to notification.star.me.notificationdemo2/.CustomBroadcastReceiver
说的是后台执行不被允许?反正搞不懂啥情况,没仔细看相关的源码。加上intent.setPackage(getPackageName());后重新编译
之后重新debug,发现这次执行了onReceiver的代码逻辑,终于找到了问题所在,就这一行代码,花去了好几个小时????,但是值得的。
参考资料
Demo下载
链接:https://pan.baidu.com/s/1Ac97_0kFxKavpQi6-YxB2w 密码:niun (demo中包含Git版本控制,可以通过切换commit,查阅动态注册,静态注册的代码)
发表于
2019-07-27 10:36 xing_star
阅读(1497)
评论(0) 编辑 收藏