突破Android O广播限制

Android O对隐式广播进行了限制, 其限制链接说明: https://developer.android.com/about/versions/oreo/background
如果应用注册为接收广播,则在每次发送广播时,应用的接收器都会消耗资源。 如果多个应用注册为接收基于系统事件的广播,这会引发问题;触发广播的系统事件会导致所有应用快速地连续消耗资源,从而降低用户体验。
为了缓解这一问题,Android 7.0(API 级别 25)对广播施加了一些限制,如后台优化中所述。
Android 8.0 让这些限制更为严格。
针对 Android 8.0 的应用无法继续在其清单中为隐式广播注册广播接收器。 隐式广播是一种不专门针对该应用的广播。 例如,ACTION_PACKAGE_REPLACED 就是一种隐式广播,因为它将发送到注册的所有侦听器,让后者知道设备上的某些软件包已被替换。
不过,ACTION_MY_PACKAGE_REPLACED 不是隐式广播,因为不管已为该广播注册侦听器的其他应用有多少,它都会只发送到软件包已被替换的应用。
应用可以继续在它们的清单中注册显式广播。
应用可以在运行时使用 Context.registerReceiver() 为任意广播(不管是隐式还是显式)注册接收器。
需要签名权限的广播不受此限制所限,因为这些广播只会发送到使用相同证书签名的应用,而不是发送到设备上的所有应用。
在许多情况下,之前注册隐式广播的应用使用 JobScheduler 作业可以获得类似的功能。
例如,一款社交照片应用可能需要不时地执行数据清理,并且倾向于在设备连接到充电器时执行此操作。
之前,应用已经在清单中为 ACTION_POWER_CONNECTED 注册了一个接收器;当应用接收到该广播时,它会检查清理是否必要。 为了迁移到 Android 8.0,应用将该接收器从其清单中移除。
应用将清理作业安排在设备处于空闲状态和充电时运行。
注:很多隐式广播当前均已不受此限制所限。 应用可以继续在其清单中为这些广播注册接收器,不管应用针对哪个 API 级别。 有关已豁免广播的列表,请参阅隐式广播例外
如何应对限制
1、将静态注册修改为动态注册
2、通过setPackage或者setComponent将隐式广播修改为显示广播,不过这种方式的话,只能发送给一个应用
3、04-21 04:12:27.513 2431 4821 W BroadcastQueue: Background execution not allowed:******************
这个log是在BroadcastQueue.java#1275中

1267                    } else if (((r.intent.getFlags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0)
1268                            || (r.intent.getComponent() == null
1269                                && r.intent.getPackage() == null
1270                                && ((r.intent.getFlags()
1271                                        & Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0)
1272                                && !isSignaturePerm(r.requiredPermissions))) {
1273                        mService.addBackgroundCheckViolationLocked(r.intent.getAction(),
1274                                component.getPackageName());
1275                        Slog.w(TAG, "Background execution not allowed: receiving "
1276                                + r.intent + " to "
1277                                + component.flattenToShortString());
1278                        skip = true;
1279                    }

r.intent.getFlags() & Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0 不能带有FLAG_RECEIVER_INCLUDE_BACKGROUND这个标志位,这就是我们实现的关键点
FLAG_RECEIVER_INCLUDE_BACKGROUND这个标志位在AS中是找不到的。

/**
 * If set, the broadcast will always go to manifest receivers in background (cached
 * or not running) apps, regardless of whether that would be done by default.  By
 * default they will only receive broadcasts if the broadcast has specified an
 * explicit component or package name.
 *
 * NOTE: dumpstate uses this flag numerically, so when its value is changed
 * the broadcast code there must also be changed to match.
 *
 * @hide
 */
public static final int FLAG_RECEIVER_INCLUDE_BACKGROUND = 0x01000000;

发送广播的时候携带intent.addFlags(0x01000000); 即能让广播突破隐式广播限制。但是这种方式AS中会提醒有错误,可以编译通过。
4、通过queryBroadcastReceivers检索接收intent的接收者
在这里插入图片描述
queryBroadcastReceivers是PackageManager中的一个检索所有Intent的接收者的方法,返回一个ResolveInfo的集合。

private static void sendImplicitBroadcast(Context ctxt, Intent i) {
		PackageManager pm=ctxt.getPackageManager();
		List<ResolveInfo> matches=pm.queryBroadcastReceivers(i, 0);
		for (ResolveInfo resolveInfo : matches) {
			Intent explicit=new Intent(i);
			ComponentName cn=
					new ComponentName(resolveInfo.activityInfo.applicationInfo.packageName,
							resolveInfo.activityInfo.name);
			explicit.setComponent(cn);
			ctxt.sendBroadcast(explicit);
		}
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值