Android O 无法接收静态广播完美解决方法

背景:两个应用需要通信,和同事讨论了一下,因为功能比较简单所以打算使用广播进行通信。写完后发现在android O上静态注册的receiver无法接收到广播。顺便就研究一下有什么方法可以解决这个问题。
代码:
举例说明,最简单的发送广播代码:

Intent intent = new Intent("com.test.broadcast.receiver");
this.sendBroadcast(intent);

接收端:

package com.example.h284333.myapplication.receiver;

public class MyReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO: This method is called when the BroadcastReceiver is receiving
        // an Intent broadcast.
        Log.d("gsy","app onreceiver ="+intent.getAction());
    }
}

在AndroidManifest中注册

<receiver
    android:name=".receiver.MyReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="com.test.broadcast.receiver" />
    </intent-filter>
</receiver>

运行后发现log没有打印出来,检查所有log发现。

BroadcastQueue: Background execution not allowed: receiving Intent { act=com.test.broadcast.receiver flg=0x10 } to com.example.h284333.myapplication/.receiver.MyReceiver

谷歌开发者网站中关于android O的说明中找到这么一段描述:

In addition, to improve device performance, the system limits certain behaviors by apps that are not running in the foreground. Specifically:
Apps cannot use their manifests to register for most implicit broadcasts (that is, broadcasts that are not targeted specifically at the app).

大概意思就是为了提高设备性能,系统限制了不在前台运行app的某些功能:
App不能使用在manifests中注册receiver的方式接收大部分的隐式广播。
为什么不是所有的隐式广播,因为有的系统的广播还是可以用静态注册方式接收的,比如开机广播,安装apk的广播。

所以只能够指定报名发送广播了,修改发送广播的代码:

ComponentName componentName = new ComponentName("com.example.h284333.myapplication","com.example.h284333.myapplication.receiver.MyReceiver");
Intent intent = new Intent("com.test.broadcast.receiver"); 
intent.setComponent(componentName);
sendBroadcast(intent);

需要注意的是componentName中指定的是你的接收器,第一个参数是接收器所在应用的包名,而不是接收器的包名。以上面的例子说明,接收器的包名是com.example.h284333.myapplication.receiver。应用的包名是com.example.h284333.myapplication。所以第一个参数应该写com.example.h284333.myapplication。第二个参数就是receiver的class名了。

运行后成功接收到广播:

08-12 01:11:44.213 12932 12932 D gsy     : app onreceiver =com.test.broadcast.receiver

但是总感觉这样就不像是一个广播,更像是一个点对点的跨进程通信方式。如果有不止一个的广播接收器总不能一一指定componentName吧。方法总是有的,
PackageManager有一个queryBroadcastReceivers方法,可以检索出指定intent的receiver。

public abstract List<ResolveInfo> queryBroadcastReceivers (Intent intent,  int flags)

Retrieve all receivers that can handle a broadcast of the given intent.

有了这个方法我们就可以给所有的receiver发送广播了,代码如下:

private void sendHXBroadCast() {
        Intent logIntent = new Intent();
        logIntent.setAction("com.test.broadcast.receiver");
        PackageManager pm=this.getPackageManager();

        List<ResolveInfo> matches=pm.queryBroadcastReceivers(logIntent, 0);
        if(matches != null && matches.size() >= 1){
            for (ResolveInfo resolveInfo : matches) {
                Intent intent=new Intent(logIntent);
                ComponentName cn=new ComponentName(
                resolveInfo.activityInfo.applicationInfo.packageName,
                                resolveInfo.activityInfo.name);
                intent.setComponent(cn);
                this.sendBroadcast(intent);
            }
        }
    }

如此便完美解决了android O 静态注册的广播接收问题了。

原创文章 4 获赞 3 访问量 1582

猜你喜欢

转载自blog.csdn.net/u012894808/article/details/88870765
今日推荐