夜间滤镜App在SDK23及以上调用startForeground时Bad Notification崩溃求解
崩溃根因排查与修复方案
首先明确:你怀疑通知ID 9216有问题是完全不成立的,只要是正整数的通知ID都不会触发Bad Notification For StartForeGround报错,这个崩溃的本质是系统判定你传给startForeground()的通知对象不符合当前API等级的强制校验规则,结合你的代码和测试场景(SDK≥23,小米Android9设备),问题全部来自通知适配的硬伤:
触发崩溃的核心问题点
1. 缺失强制要求的通知渠道
这是API26以上设备触发该崩溃最常见的原因,从Android 8.0(API 26)开始,所有提交给系统的通知必须绑定一个提前注册的NotificationChannel,没有渠道绑定的通知是完全无效的空对象。
你之前在低版本SDK(<23,Android6.0以下)设备上运行正常,是因为早期系统没有渠道机制,但到了API26以上的设备,哪怕你用了NotificationCompat兼容库,只要没做渠道注册,构建出来的通知就通不过系统校验,直接传给startForeground()必然触发崩溃。
2. 通知属性不符合定制ROM校验规则
你代码里的几个细节刚好踩中了小米MIUI的校验红线:
- smallIcon(你用的
R.drawable.red1)如果是不透明的彩色图片,不符合Android5.0以上对通知小图标的规范要求,MIUI会直接判定通知无效 - 强制把通知的
when设为0L,在MIUI的部分Android9版本上,这种异常时间戳的通知会被判定为无效对象 - 用自定义RemoteViews做通知时,没有搭配基础的
contentTitle、contentText属性,系统在加载自定义RemoteViews失败的场景下,会因为缺少兜底的通知内容直接判定无效
3. 代码逻辑硬伤
你给按钮设置点击事件的代码存在明显错误:
remoteViews.setOnClickPendingIntent(R.id.btn1, pendingIntent); remoteViews.setOnClickPendingIntent(R.id.btn2, pendingIntent);
两个功能完全不同的按钮绑定了同一个PendingIntent,虽然不会直接导致崩溃,但会进一步增加RemoteViews的校验失败概率。
分步修复操作
- 第一步:在Service初始化阶段完成通知渠道注册,所有API26以上设备运行时,必须先注册渠道才能构建通知:
构建通知时,必须把对应渠道ID传入Builder构造函数:// 在Service的onCreate方法中添加 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { String channelId = "night_filter_service_channel"; NotificationChannel channel = new NotificationChannel( channelId, "夜间滤镜前台服务通知", NotificationManager.IMPORTANCE_LOW ); channel.setShowBadge(false); NotificationManager manager = getSystemService(NotificationManager.class); manager.createNotificationChannel(channel); }// 修正之前的无渠道构造写法 NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId) - 第二步:替换smallIcon为符合系统规范的透明轮廓图标,不要使用不透明的彩色图当小图标,避免被定制ROM判定无效
- 第三步:修正按钮的PendingIntent绑定错误,给btn1、btn2分别绑定对应开关逻辑的PendingIntent,同时去掉
setWhen(0L)的硬编码,使用系统默认的时间戳即可 - 第四步:在自定义RemoteViews的通知基础上,补充基础的兜底通知属性,哪怕RemoteViews加载失败,系统也能拿到合法的通知内容通过校验:
builder.setContentTitle(getString(R.string.app_name)) .setContentText("夜间滤镜正在运行") - 第五步:增加兜底异常捕获,避免极端场景下系统校验失败直接crash:
try { startForeground(9216, notification); } catch (Exception e) { // 构建最简合规通知做兜底 Notification fallback = new NotificationCompat.Builder(this, channelId) .setSmallIcon(R.drawable.red1) .setContentTitle(getString(R.string.app_name)) .setContentText("夜间滤镜正在运行") .build(); startForeground(9216, fallback); }
内容的提问来源于stack exchange,提问作者PArikshit KAmat
相关产品推荐
相关产品推荐

