Manifest-declared BroadcastReceiver not picking up

2019-05-12 00:46发布

问题:

I am trying to get two apps to communicate via broadcasts. The first app sends a broadcast using code like the following:

Intent outIntent = new Intent("org.example.WHATEVER");
PackageManager pm = this.getPackageManager();
List<ResolveInfo> receivers = pm.queryBroadcastReceivers(outIntent, 0);
if (receivers != null)
    for (ResolveInfo receiver : receivers) {
        Log.d("Sender", String.format("Polling %s", receiver.activityInfo.packageName));
        outIntent = new Intent("org.example.WHATEVER");
        outIntent.setPackage(receiver.activityInfo.packageName);
        sendBroadcast(outIntent);
    }

The receiving end registers a BroadcastReceiver in its manifest:

<receiver android:name="org.example.receiverapp.WhateverReceiver" >
    <intent-filter>
        <action android:name="org.example.WHATEVER" />
    </intent-filter>
</receiver>

The onReceive() method writes a log entry when invoked.

When the receiving app is running (i.e. I’ve had its main activity on screen, then navigated away from it), it processes the broadcast. However, if the receiver app is not running (which I ensure by long-pressing Back, having activated “Long-press Back to kill app” in Developer Settings), it is not woken up by the broadcast.

I am deliberately setting a package name for the intent, to avoid issues with manifest-declared receivers no longer receiving implicit broadcasts from Android 8 onwards. Besides, I am running Android 7, with both apps targeting API 23, thus any restrictions in Android 8 should not matter in this setup anyway.

I’ve come across a comment whose author suggests that certain flavors of Android may not wake applications for broadcasts, which seems to be what I am experiencing here (running LineageOS 14.1)—though that comment isn’t very specific and I haven’t found anything else backing this claim.

Is this what is happening here? If so, how can I ensure the receiver app is woken up by the broadcast (at least if it is directed)? If not, what’s wrong here?

回答1:

To make an explicit Intent, I usually use setComponent(), as it is guaranteed to work (as much as anything is):

Intent outIntent = new Intent("org.example.WHATEVER");
PackageManager pm = this.getPackageManager();
List<ResolveInfo> receivers = pm.queryBroadcastReceivers(outIntent, 0);
if (receivers != null)
    for (ResolveInfo receiver : receivers) {
        Log.d("Sender", String.format("Polling %s/%s",
                receiver.activityInfo.applicationInfo.packageName,
                receiver.activityInfo.name));
        ComponentName cn = new ComponentName(
                receiver.activityInfo.applicationInfo.packageName,
                receiver.activityInfo.name);
        outIntent = new Intent("org.example.WHATEVER");
        outIntent.setComponent(cn);
        sendBroadcast(outIntent);
    }

In some cases, setPackage() makes an Intent "explicit enough" to satisfy some Android criterion. Apparently in this case, it does not. ¯\_(ツ)_/¯