Android14 平凡应用registerReceiver注册广播报错One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be

[复制链接]
发表于 2026-4-24 09:03:25 | 显示全部楼层 |阅读模式
Android14 平凡应用registerReceiver注册广播报错One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified …



一、前言

Android14 平凡应用注册广播registerReceiver会报错,提示须要添加一个参数RECEIVER_EXPORTED 大概 RECEIVER_NOT_EXPORTED;体系framework大概体系应用是不会报这个错误的!
这个题目比力好办理,加一个参数就行,但是网上现在没有人对这个题目本日深入分析。
本文对registerReceiver报错举行分析,具体到哪个类哪行代码报错,
分析相识后对于体系其他相干报错能有个认识,大概有分析思绪。
RECEIVER_EXPORTED 体现外部应用范围,RECEIVER_NOT_EXPORTED 体现非外部应用范围,是否有作用?
二、Google 对Android14 广播阐明

阐明图片所示:

对于Android14 紧张阐明内容:
  1. For apps targeting Build.VERSION_CODES.UPSIDE_DOWN_CAKE, either RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED must be specified if the receiver is not being registered for system broadcasts or a SecurityException will be thrown. See registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, int) to register a receiver with flags.
复制代码
Build.VERSION_CODES.UPSIDE_DOWN_CAKE 是Android14的名称,旋转蛋糕。
上面的英文大概意思:
  1. 对于以Build为 Android14的应用程序版本代码
  2. 如果接收器没有为系统广播注册,或者将引发SecurityException,
  3. 则必须指定RECEIVER_EXPORTED或RECEIVE_NOT_EXPORTED。
  4. 请参阅registerReceiver(android.content.BroadcastReceiver,android.contant.IntentFilter,int)注册带有标志的接收器。
复制代码
相干网址:https://developer.android.google.cn/reference/android/content/Context
搜索 registerReceiver 就大概找到相干代码。
三、Android14 注册广播报错办理和分析

1、报错示例息争决方法

Android平凡应用的注册广播的代码:
  1. public class MainActivity extends AppCompatActivity {
  2.     public void testBroadcast(View view) { //点击按钮,监听广播
  3.         LogUtil.debug("");
  4.         IntentFilter intentFilter = new IntentFilter();
  5.         intentFilter.addAction("aa");        
  6.         //registerReceiver(mReceiver1, intentFilter);//在这里报错,如果没有try catch,会崩溃
  7.         
  8.         //解决方法:添加一个参数Context.RECEIVER_EXPORTED 或者ContextRECEIVER_NOT_EXPORTED
  9.         //RECEIVER_EXPORTED 表示可以接收应用外部广播,ContextRECEIVER_NOT_EXPORTED 应用内部广播
  10.         registerReceiver(mReceiver2, intentFilter, Context.RECEIVER_EXPORTED);
  11.     }
  12.     private BroadcastReceiver mReceiver1 = new BroadcastReceiver() {
  13.         @Override
  14.         public void onReceive(Context context, Intent intent) {
  15.             String action = intent.getAction();
  16.              LogUtil.debug("action = " + action);
  17.         }
  18.     }
复制代码
上面代码就包罗了报错的代码示例和准确的写法。
在Android13大概更早的版本,上面的代码都是没有题目标;只有Android14 会报错。
2、报错分析

报错的堆栈信息:

报错最紧张相干日志日志
  1.                  Caused by: java.lang.SecurityException: com.demo.android14demo: One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified when a receiver isn't being registered exclusively for system broadcasts
  2.                 at android.app.IActivityManager.registerReceiverWithFeature
  3.         at android.app.ContextImpl.registerReceiverInternal(ContextImpl.java:1852)
  4.         at android.app.ContextImpl.registerReceiver(ContextImpl.java:1792)
  5.         at android.app.ContextImpl.registerReceiver(ContextImpl.java:1780)
  6.         at android.content.ContextWrapper.registerReceiver(ContextWrapper.java:755)
  7.         at com.demo.android14demo.MainActivity.testBroadcast(MainActivity.java:25)
  8.      Caused by: android.os.RemoteException: Remote stack trace:
  9.         at com.android.server.am.ActivityManagerService.registerReceiverWithFeature(ActivityManagerService.java:13927)
复制代码
从报错日志日志看,MainActivity 注册广播后,ContextImpl.registerReceiverInternal 之后就报错了;
岂非报错信息在 ContextImpl.java 代码内里?
查察 ContextImpl.java 源码,并没有发现报错判定和相干关键字,以是是在往下的逻辑举行的报错。
着实就是 IActivityManager的实现类 ActivityManagerService 内里报错的:
release\frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
  1. public Intent registerReceiverWithFeature(... IIntentReceiver receiver,
  2. IntentFilter filter, String permission, int userId, int flags) {
  3.                         //(1)判断是否设置了RECEIVER_EXPORTED 或者 RECEIVER_NOT_EXPORTED 的flag
  4.             final boolean explicitExportStateDefined =
  5.                     (flags & (Context.RECEIVER_EXPORTED | Context.RECEIVER_NOT_EXPORTED)) != 0;
  6.                         //(2)动态接收广播,这里有判断 callingUid 应用等级,可能是系统应用没有报错的原因
  7.             boolean requireExplicitFlagForDynamicReceivers = CompatChanges.isChangeEnabled(
  8.                     DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED, callingUid);
  9.             if (!onlyProtectedBroadcasts) { //(3)非保护广播
  10.                 if (receiver == null && !explicitExportStateDefined) {
  11.                     // sticky broadcast, no flag specified (flag isn't required)
  12.                     flags |= Context.RECEIVER_EXPORTED;
  13.                 } else if (requireExplicitFlagForDynamicReceivers && !explicitExportStateDefined) {//(4)未设置flag和动态注册的广播---抛出异常
  14.                     throw new SecurityException(
  15.                             callerPackage + ": One of RECEIVER_EXPORTED or "
  16.                                     + "RECEIVER_NOT_EXPORTED should be specified when a receiver "
  17.                                     + "isn't being registered exclusively for system broadcasts");
  18.                     // Assume default behavior-- flag check is not enforced
  19.                 } else if (!requireExplicitFlagForDynamicReceivers && (
  20.                         (flags & Context.RECEIVER_NOT_EXPORTED) == 0)) {
  21.                     // Change is not enabled, assume exported unless otherwise specified.
  22.                     flags |= Context.RECEIVER_EXPORTED;
  23.                 }
  24.             } else if ((flags & Context.RECEIVER_NOT_EXPORTED) == 0) {
  25.                 flags |= Context.RECEIVER_EXPORTED;
  26.             }
  27.         }
  28. }
复制代码
Android14注册广播报错是在 ActivityManagerService.java 内里一些列判定之后抛出非常报错的。
四、其他

1、Android14 registerReceiver注册广播报错总结

平凡应用须要再末了添加参数Context.RECEIVER_EXPORTED 大概 Context.RECEIVER_NOT_EXPORTED;
Android13 大概更低版本测试了并没有这个题目。
着实 Android13 的ActivityManagerService.java也是有大抵的流程,也会抛出谁人非常过程,
至于为啥没有报错,应该是具体判定内里的流程中,某个属性值的返回有差异以是没进入到抛出非常的过程。
2、Android13 开始AndroidManifest.xml内里的四大组件都是要界说exported属性的,否则会编译报错

activity、service、receiver、provider 这个四大组件都是必须设置 exported 属性,否则会报错
  1.         <activity android:name=".MainActivity" android:exported="true">
  2.             <intent-filter>
  3.                 <action android:name="android.intent.action.MAIN" />
  4.                 <category android:name="android.intent.category.LAUNCHER" />
  5.             </intent-filter>
  6.         </activity>
复制代码
纵然是Android Studio新建的项目,activity也要添加exported属性,否则编译错误。
3、Context.RECEIVER_EXPORTED 和Context.RECEIVER_NOT_EXPORTED作用?

从字面意思看:EXPORTED体现外部应用,NOT_EXPORTED体现非外部应用,即本应用内。
以是Context.RECEIVER_EXPORTED体现可以汲取外部的广播,
Context.RECEIVER_NOT_EXPORTED体现只能汲取应用内的广播?
从现在现实测试结果看,并非云云。
测试体系自动广播和app自界说广播,demo示例汲取广播,Action代码:
  1. IntentFilter mFilter = new IntentFilter();
  2. mFilter.addAction("action.mytest"); //自定义action
  3. mFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);//网络变化广播
  4. mFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); //wifi开关广播
  5. mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
  6. mFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
  7. mFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
  8. mFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
  9. registerReceiver(mReceiver1, mFilter, Context.RECEIVER_EXPORTED);
复制代码
监听广播不管设置Context.RECEIVER_EXPORTED还是Context.RECEIVER_NOT_EXPORTED,
都是可以汲取到网络厘革的广播和其他应用自界说发出的广播。
以是从现实来看:
  1. Context.RECEIVER_EXPORTED和Context.RECEIVER_NOT_EXPORTED其实没啥区别,效果是一样的。
复制代码
也就是说 Context.RECEIVER_NOT_EXPORTED 限定只继承应用内广播,并不会起作用。
但是最好还是都设置成 Context.RECEIVER_EXPORTED ,由于我看了 ActivityManagerService.java 的源码,
发现 Context.RECEIVER_NOT_EXPORTED 的情况有更多判定,以致有抛出非常的大概!
Android 14 ActivityManagerService.java:
  1. public class ActivityManagerService extends IActivityManager.Stub {
  2. ...
  3.     public Intent registerReceiverWithFeature(...IntentFilter filter) {
  4.         enforceNotIsolatedCaller("registerReceiver");
  5.         ...
  6.         }
  7. /* package */ void enforceNotIsolatedCaller(String caller) {
  8.         if (UserHandle.isIsolated(Binder.getCallingUid())) { //Isolated 表示远程的,外部的
  9.             throw new SecurityException("Isolated process not allowed to call " + caller);
  10.         }
  11.     }
  12. }
复制代码
从现在情况看,并不会抛出这个非常(外部应用不答应监听)。
Android13 ActivityManagerService.java代码中,
设置了Context.RECEIVER_NOT_EXPORTED 才会进入判定 enforceNotIsolatedCaller :
  1. if ((flags & Context.RECEIVER_NOT_EXPORTED) != 0) {
  2.             enforceNotIsolatedCaller("registerReceiver");
  3.         }
复制代码
着实上面代码只是分析了Android14报错,但是并没有分析Android13 的代码为啥不会报错,
具体是那边的差异,在源码中并未看到,有爱好的同砚本身可以举行研究看看。
4、ActivityManagerService.java 的源码

Android13 ActivityManagerService.java:
http://aospxref.com/android-13.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
Android14 ActivityManagerService.java:
http://aospxref.com/android-14.0.0_r2/xref/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
Android 体系其他代码也可以使用网址查察:http://aospxref.com 。
寄语:来日诰日五一,劳动节快乐。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表