Android 14(SDK34)动态注册广播接收器报SecurityException解决
解决Android 14(SDK 34)动态注册BroadcastReceiver的SecurityException错误
问题背景
原有动态注册BroadcastReceiver的代码在SDK版本低于34时运行正常,但升级到Android 14(SDK 34)后抛出如下SecurityException:
java.lang.SecurityException: One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified when a receiver isn't being registered exclusively for system broadcasts
原注册逻辑:通过包名拼接的自定义action注册接收器,收到广播后自动注销并启动主页面。
错误原因
Android 14(API 34)新增强制安全规则:非系统专属的广播接收器,必须明确声明是否允许其他应用触发,需通过RECEIVER_EXPORTED或RECEIVER_NOT_EXPORTED标记指定接收器的暴露状态。
解决方案
根据广播的使用场景选择对应标记,再修改注册代码兼容高低版本:
1. 确定广播使用范围
- 如果仅当前应用内部收发(比如你的
SYNC_NOTIFY是应用内部同步通知):用RECEIVER_NOT_EXPORTED,这是更安全的选择,避免其他应用恶意触发。 - 如果需要允许其他应用触发:用
RECEIVER_EXPORTED,你的action已用包名拼接,唯一性有保障,无需额外调整。
2. 修改注册代码
针对Android 14及以上版本添加标记参数,低版本沿用原有逻辑:
private void registerReceiver() { try { IntentFilter intentFilter = new IntentFilter(Config.getUCHAction(getApplicationContext(), SYNC_NOTIFY)); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { // 对应Android 14,API 34 // 根据场景选择RECEIVER_NOT_EXPORTED或RECEIVER_EXPORTED registerReceiver(syncStatusReceiver, intentFilter, Context.RECEIVER_NOT_EXPORTED); } else { // 低版本无需指定标记 registerReceiver(syncStatusReceiver, intentFilter); } } catch (Exception e) { e.printStackTrace(); } }
也可以兼容到Android 13(API 33),该版本已支持这两个标记,只是Android 14强制要求:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { // Android 13,API 33 registerReceiver(syncStatusReceiver, intentFilter, Context.RECEIVER_NOT_EXPORTED); }
内容的提问来源于stack exchange,提问作者Krishna Dhas
相关产品推荐
相关产品推荐

