BroadCastReceiver 是 Android 四大组件之一,应用非常广泛,作为 Android 组件间的通信方式,主要使用的场景如下:
- 同一app内部的同一组件内的消息通信(单个或多个线程之间)
- 同一app内部的不同组件之间的消息通信(单个进程)
- 同一app具有多个进程的不同组件之间的消息通信
- 不同app之间的组件之间消息通信
- Android系统在特定情况下与App之间的消息通信
但是,我们在使用广播进行消息通信的过程中,很容易忽略了安全问题。别人可以通过广播向我们的广播接收器发送恶意数据,也可以注册我们的广播接收器,来接收我们传递的数据,这两种情况都是我们不想看到的。
那么如何避免以上两种情况呢?在解决这个问题之前,我们先来了解一下广播。
广播实现原理
Android中的广播使用了观察者模式,基于消息的发布/订阅事件模型。因此,从实现的角度来看,Android中的广播将广播的发送者和接受者极大程度上解耦,使得系统能够方便集成,更易扩展。具体实现流程要点粗略概括如下:
- 广播接收者 BroadcastReceiver 通过 Binder 机制向 AMS(Activity Manager Service) 进行注册
- 广播发送者通过 Binder 机制向 AMS 发送广播
- AMS 查找符合相应条件(IntentFilter/Permission等)的 BroadcastReceiver,将广播发送到 BroadcastReceiver(一般情况下是Activity)相应的消息循环队列中
- 消息循环执行拿到此广播,回调BroadcastReceiver中的onReceive()方法
因此,广播发送者和广播接收者分别属于观察者模式中的消息发布和订阅两端,AMS属于中间的处理中心。广播发送者和广播接收者的执行是异步的,发出去的广播不会关心有无接收者接收,也不确定接收者到底是何时才能接收到。
广播的注册方式
广播的注册方式分为两种:静态注册 和 动态注册。
- 静态注册
直接在AndroidManifest.xml文件中进行注册,例子如下:
<receiver android:name=".MyBroadcastReceiver" ><intent-filter><action android:name="android.net.conn.CONNECTIVITY_CHANGE" /></intent-filter><intent-filter><action android:name="android.intent.action.BOOT_COMPLETED" /></intent-filter>
</receiver>
- 动态注册
通过调用Context的registerReceiver函数,可以在程序中动态注册BroadcastReceiver,例子如下:
mBroadcastReceiver = new MyBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
intentFilter.addAction("android.intent.action.BOOT_COMPLETED");
registerReceiver(mBroadcastReceiver, intentFilter);
广播安全解决方案
- 在静态注册广播是添加
android:exported="false"
属性,禁止本应用的广播接收器响应其他应用的广播。
<receiver android:name="com.xiuxiuing.MyBroadCastReceiver" android:exported="false"> <intent-filter > ...</intent-filter> </receiver>
- 动态注册广播时,通过报名设置
intent.setPackage("com.xiuxiuing.demo")
,来决定你的广播对那个应用有效。
Intent intent=new Intent("com.xiuxiuing.action");
intent.setPackage("com.xiuxiuing.demo");
this.sendBroadcast(intent);
- 使用
LocalBroadcastManager
来实现进程内广播,其他进程无法接收广播信息,注意:同一应用的其他进程也接收不到广播信息。
// 发送广播
Intent intent = new Intent("com.xiuxiuing.action");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);// 接收广播IntentFilter filter = new IntentFilter(); filter.addAction("com.xiuxiuing.action"); mReceiver = new MyBroadCastReceiver(); mLocalBroadcastManager = LocalBroadcastManager.getInstance(this); mLocalBroadcastManager.registerReceiver(mReceiver, filter);
- 使用
sendBroadcast(Intent intent, receiverPermission)
发送权限广播,只有具有这个权限的应用才能处理这个广播。
// 广播发送
Intent intent = new Intent("com.xiuxiuing.action");
sendBroadcast(intent,"com.xiuxiuing.custom.permission");// 广播接收
// 在接收广播的APP 的 Manifest.xml文件中添加自定义权限<uses-permission android:name="com.xiuxiuing.custom.permission" /><permissionandroid:name="com.xiuxiuing.custom.permission"android:protectionLevel="normal"></permission>// 注册广播接收器IntentFilter filter = new IntentFilter(); filter.addAction("com.xiuxiuing.action"); mReceiver = new MyBroadCastReceiver(); registerReceiver(mReceiver, filter);
- 使用
registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler)
注册广播,只处理具有这个权限的APP发送的广播。
// 广播发送
// 在发送广播的APP 的 Manifest.xml文件中添加自定义权限<uses-permission android:name="com.xiuxiuing.custom.permission" /><permissionandroid:name="com.xiuxiuing.custom.permission"android:protectionLevel="normal"></permission>// 发送广播
Intent intent = new Intent("com.xiuxiuing.action");
sendBroadcast(intent);// 广播接收IntentFilter filter = new IntentFilter(); filter.addAction("com.xiuxiuing.action"); mReceiver = new MyBroadCastReceiver(); registerReceiver(mReceiver, filter, "com.xiuxiuing.custom.permission", null);
以上五种广播的安全解决方案,你可以根据自己的理解,选择适合自己项目的方案。