Android O 应该快要发布正式版了,和 N 一样又是一个用户乍一看在表面上没什么改变的版本,但其实对安全、隐私和规范应用行为做了很多改变

改变中很重要的一部分就是后台执行限制,其中就有对广播(Broadcast)的限制 ,许多隐式广播无法被在 manifest 中静态注册的 BroadcastReceiver 收到。

除了这些由系统发出的隐式广播之外,我们在自己应用里定义的广播也无法被静态注册的 BroadcastReceiver 收到了。
以下是几个解决方案:

1.动态注册 BroadcastReceiver

因为 registerReceiver() 方法只能从一个运行的进程里调用,也就是说你需要一个正在运行的 Activity 或者一个后台 Service ,这样的方法虽然万用但是这个进程终究会被 kill 导致广播收不到。

2.JobScheduler

官方推荐使用 JobScheduler 代替原来用隐式广播实现的「当某条件达成时发生广播完成某事」的「周期性」功能,并没有广播那么灵活。

3.改为显式广播

如果广播只是 App 自己发自己收,那么改为显式广播是最简单的。

1
2
3
intent.action = "com.example.test.CLOSE”;
intent.setPackage(getPackageName()); //指定包名
context.sendBroadcast(intent);

但是如果要发给其他 App 接收,而且不知道他们的包名的情况下,该怎么做的。
通过pm把所有隐式注册了这个自定义广播的 App列出来,然后转成显式调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Intent intent = new Intent();    
intent.setAction("com.example.test.CLOSE");   
sendImplicitBroadcast(context, intent);

private static void sendImplicitBroadcast(Context context, Intent i) {       
PackageManager pm = context.getPackageManager();       
List<ResolveInfo> matches = pm.queryBroadcastReceivers(i, 0);
for (ResolveInfo resolveInfo : matches) {           
Intent intent = new Intent(i);           
intent.setPackage(resolveInfo.activityInfo.applicationInfo.packageName);           
intent.setAction("com.example.test.CLOSE");           
context.sendBroadcast(intent);       
}
}

 

参考:https://commonsware.com/blog/2017/04/11/android-o-implicit-broadcast-ban.html