为什么清单声明的监听显式广播的BroadcastReceiver运行一段时间后停止工作?
问题原因
- Android 9及以上版本引入的**应用待机分组(App Standby Buckets)**机制:长时间未被用户主动打开的App会被划入
rare/restricted分组,系统会主动拦截投递到该应用的静态广播,即使是显式广播也会被限制。 - 应用停止状态拦截:如果App B被系统主动回收并标记为停止状态,默认情况下系统不会给停止状态的应用投递任何广播,你的代码当前没有针对这种场景做适配。
- 部分国产ROM的定制后台限制:小米、华为、OPPO等厂商的定制系统会额外增加后台管控逻辑,长时间无活跃的应用的静态广播接收器会被直接冻结,不会响应广播事件。
解决方案
无需App B申请任何权限的方案(优先推荐)
仅需修改App A的发送逻辑,无需调整App B的任何代码,也不需要用户授权:
- 给广播Intent添加
FLAG_INCLUDE_STOPPED_PACKAGES标记,强制系统向已处于停止状态的应用投递广播,修改后的发送代码如下:
Intent intent = new Intent(); intent.setAction("com.example.NOTIFICATIONBROADCSTACTION"); // 新增此行,绕过停止状态应用的广播拦截 intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); putIntentExtras(intent,m); PackageManager packageManager = getPackageManager(); List<ResolveInfo> infos = packageManager.queryBroadcastReceivers(intent, 0); for (ResolveInfo info : infos) { ComponentName cn = new ComponentName(info.activityInfo.packageName, info.activityInfo.name); intent.setComponent(cn); sendOrderedBroadcast(intent, null, bc,null, MainActivity.RESULT_CANCELED,null,null); }
- 你当前使用的显式广播写法已经绕过了Android 8.0的隐式静态广播限制,无需调整该部分逻辑。
需少量用户授权的方案(适合高稳定性要求场景)
如果上述方案在部分定制ROM上仍不生效,可以采用以下方案:
- App B申请电池优化白名单权限:该权限仅需弹出系统级确认弹窗,不需要用户手动到设置页授权,申请后App不会被系统电池优化策略限制,不会被划入高限制级的待机分组。
在App B中新增授权逻辑即可:if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { String packageName = getPackageName(); PowerManager pm = getSystemService(PowerManager.class); if (!pm.isIgnoringBatteryOptimizations(packageName)) { Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); intent.setData(Uri.parse("package:" + packageName)); startActivity(intent); } } - 引导用户开启App B的后台权限:针对国产定制ROM,可在App B首次启动时弹出引导页,引导用户开启「自启动」「后台活动」权限,不同ROM的引导逻辑可根据厂商公开的适配文档开发。
- 双App联动唤醒:如果两个应用均由你开发,可以在App B中注册一个空的ContentProvider,App A发送广播前先访问该ContentProvider唤醒App B进程,再发送广播即可100%触达,不需要额外权限。
内容的提问来源于stack exchange,提问作者flopfl
相关产品推荐
相关产品推荐

