接收广播
在manifest文件中声明receiver
<receiver android:name=".MyBroadcastReceiver" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.INPUT_METHOD_CHANGED" />
</intent-filter>
</receiver>
public class MyBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "MyBroadcastReceiver";
@Override
public void onReceive(Context context, Intent intent) {
StringBuilder sb = new StringBuilder();
sb.append("Action: " + intent.getAction() + "\n");
sb.append("URI: " + intent.toUri(Intent.URI_INTENT_SCHEME).toString() + "\n");
String log = sb.toString();
Log.d(TAG, log);
Toast.makeText(context, log, Toast.LENGTH_LONG).show();
}
}
通过context注册receiver
receiver只在组件存活期间有效。
不需要receiver时要及时unregister。如在Activity中onCreate()中注册,则在onDestroy()中反注册;在onResume()中注册,则在onPause()中反注册。
BroadcastReceiver br = new MyBroadcastReceiver();
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
intentFilter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
this.registerReceiver(br, filter);
对进程状态的影响
receiver所在的进程只在执行onReceive()方法时是前台进程,如果进程中没有运行其他组件,则进程在执行完onReceive()方法后很可能会被系统回收。
在onReceive()中执行异步操作,可以使用goAsync(),或者通过JobScheduler来安排一个JobService。
public class MyBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "MyBroadcastReceiver";
@Override
public void onReceive(final Context context, final Intent intent) {
final PendingResult pendingResult = goAsync();
AsyncTask<String, Integer, String> asyncTask = new AsyncTask<String, Integer, String>() {
@Override
protected String doInBackground(String... params) {
StringBuilder sb = new StringBuilder();
sb.append("Action: " + intent.getAction() + "\n");
sb.append("URI: " + intent.toUri(Intent.URI_INTENT_SCHEME).toString() + "\n");
Log.d(TAG, log);
// Must call finish() so the BroadcastReceiver can be recycled.
pendingResult.finish();
return data;
}
};
asyncTask.execute();
}
}
发送广播
- sendOrderedBroadcast(Intent, String)。串行有序地向receiver发送广播。
- sendBroadcast(Intent)
- LocalBroadcastManager.sendBroadcast
LocalBroadcastManager的主要方法:
- registerReceiver()
- unregisterReceiver()
- sendBroadcast()
设置权限
发送广播时设置权限
可以设置系统已有的权限,也可以设置自定义权限(通过sendBroadcast(Intent, String)
或者sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
。
sendBroadcast(new Intent("com.example.NOTIFY"),
Manifest.permission.SEND_SMS);
接收该广播时,接收方app需要设置以下权限:
<uses-permission android:name="android.permission.SEND_SMS"/>
接收广播时设置权限
只有设置了该权限的广播才能够向receiver发送广播。
<receiver android:name=".MyBroadcastReceiver"
android:permission="android.permission.SEND_SMS">
<intent-filter>
<action android:name="android.intent.action.AIRPLANE_MODE"/>
</intent-filter>
</receiver>
或
java
IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
registerReceiver(receiver, filter, Manifest.permission.SEND_SMS, null );
广播发送方需设置以下权限:
<uses-permission android:name="android.permission.SEND_SMS"/>
基于安全考虑的最佳实践
- 不需要向其他app发送广播时,使用Support Library中的LocalBroadcastManager。
- 优先使用context注册receiver。
- 限制可以接收到广播的receiver:
- 广播设置权限;
- Android 4.0及以上,可以对广播setPackage(String),只向相同包名的app发送广播;
- 使用LocalBroadcastManager。
- 限制receiver能够接收到的广播:
- receiver设置权限;
- manifest中设置的receiver,可以设置android:exported为false;
- 使用LocalBroadcastManager。
- Action的名称需全局唯一。
- 不要在onReveive()中做耗时操作,如有需要可以使用子线程或后台Service。
- 不要在onReceive()中start activities。