Android 14中ContextCompat.registerReceiver的RECEIVER_NOT_EXPORTED报错排查
我的代码
val intentFilter = IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { ContextCompat.registerReceiver( requireActivity(), smsBroadcastReceiver, intentFilter, ContextCompat.RECEIVER_NOT_EXPORTED ) }else { requireActivity().registerReceiver(smsBroadcastReceiver, intentFilter) }
以上是我用于处理短信验证码的代码,目前在Android 14设备上出现崩溃,问题和Google针对广播接收器的政策变更有关。
Android Studio在RECEIVER_NOT_EXPORTED行显示错误,提示信息如下:
必须是以下选项之一:
androidx.core.content.ContextCompat.RECEIVER_VISIBLE_TO_INSTANT_APPS,
androidx.core.content.ContextCompat.RECEIVER_EXPORTED,
androidx.core.content.ContextCompat.RECEIVER_NOT_EXPORTED
我明明已经使用了androidx.core.content.ContextCompat.RECEIVER_NOT_EXPORTED,但错误依然存在,请问哪里操作错了?该怎么修复?
另外,Firebase控制台里的崩溃日志如下:
Fatal Exception: java.lang.SecurityException
org.samagra.missionPrerna: One of RECEIVER_EXPORTED or
RECEIVER_NOT_EXPORTED should be specified when a receiver isn't being
registered exclusively for system broadcasts
我的项目targetSdkVersion和compileSdkVersion都是34,Gradle依赖已经包含最新版的androidx.core:core-ktx:1.12.0和androidx.appcompat:appcompat:1.6.1,但RECEIVER_NOT_EXPORTED标记还是报错。
修复方案
1. 统一使用兼容注册方法,移除手动版本判断
ContextCompat.registerReceiver本身已经做了全版本兼容处理,不需要自己写SDK版本分支逻辑,直接统一调用并传入导出标记即可,这样能避免手动判断可能出现的逻辑漏洞:
val intentFilter = IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION) ContextCompat.registerReceiver( requireActivity(), smsBroadcastReceiver, intentFilter, ContextCompat.RECEIVER_NOT_EXPORTED )
该方法会自动在Android 13及以下版本忽略导出标记,完全符合系统要求。
2. 检查依赖版本与导入路径
- 确认
RECEIVER_NOT_EXPORTED的导入来源是androidx.core.content.ContextCompat,而非android.content.Context(后者仅在API 33+存在,兼容性不如前者)。 - 尝试升级
androidx.core依赖到1.13.0或更高版本,部分旧版本的core库存在常量识别的兼容性问题,升级后可解决IDE报错。
3. 清理IDE缓存并重构项目
IDE缓存可能导致常量识别异常,执行以下操作:
- 清理缓存:
File -> Invalidate Caches... -> Invalidate and Restart - 同步Gradle:点击工具栏
Sync Project with Gradle Files按钮 - 重构项目:
Build -> Rebuild Project
4. 确认广播属性
SmsRetriever.SMS_RETRIEVED_ACTION属于Google Play服务发送的非系统核心广播,必须指定导出标记。由于该广播只有你的App和Google Play服务能发送,使用RECEIVER_NOT_EXPORTED是安全合规的。
内容的提问来源于stack exchange,提问作者Ujjwal Saxena

