Android O:不允许后台执行:经许可的自定义广播

Android O : Background execution not allowed: Custom broadcast with permission

在我的应用程序中,我已经为另一个受权限保护的应用程序的隐式广播注册了一个广播接收器:

<receiver
    android:name=".receiver.MyReceiver"
    android:exported="true"
    android:permission="owner.custom.permission">
    <intent-filter>
        <action android:name="owner.custom.broadcast"/>
    </intent-filter>
</receiver>

MyReceiver#onReceive() 中,我正在使用 enqueueWork():

调用 JobIntentService MyService
public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(final Context context, final Intent intent) {
        Log.i(TAG, "Received the broadcast");
        MyService.enqueueWork(context, getServiceIntent(context));
    }

    private Intent getServiceIntent(final Context context) {
        final Intent intent = new Intent(context, MyService.class);
        intent.putExtra("someKey", true);
        return intent;
    }
}

我在 MyService 中有以下方法:

public static void enqueueWork(final Context context, final Intent work) {
        enqueueWork(context, MyService.class, 111, work);
    }

现在每当 owner.custom.broadcast 广播时, MyReceiver 不会被触发,我可以看到以下日志:

07-23 03:56:29.755  3335  3361 W BroadcastQueue: Background execution not allowed: receiving Intent { act=owner.custom.broadcast flg=0x10 } to com.amazon.myApp/.receiver.MyReceiver

现在我正在收听另一个这样的第 3 方隐式广播,使用不同的广播接收器并在那边调用 MyService,它工作正常。我也在另一个广播接收器中收听 BOOT_COMPLETED 广播并在那里调用 MyService 并且在那里也工作正常。
这个错误的可能原因是什么,这将帮助我确定我是否遗漏了什么。

更新:
我现在只是想让广播接收器触发,但我仍然遇到同样的错误。我正在尝试接收器中的日志行:

public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(final Context context, final Intent intent) {
        Log.i(TAG, "Received the broadcast");
    }
}

试试这个

I faced a similar problem year ago, I'm not pretty sure of this, but since its not allowed for background execution then execute it in foreground using Foreground Service, you can achieve that by starting a service that is connected to a notification, then in your service you can trigger your broadcast and that should work.

希望我的回答对你有所帮助

我不确定为什么这个解决方案有效(也许其他人可以详细说明原因)但是我能够通过在我的清单本身中声明权限并使用它来触发我的广播接收器。在下面找到代码更改:

<permission
    android:name="owner.custom.permission"
    android:protectionLevel="signatureOrSystem">
</permission>
.
.
.
<uses-permission android:name="owner.custom.permission" />

Android O 限制隐式广播,不能在接收者中执行后台服务。

但是,它只限制静态接收器,您可以在代码中注册您的接收器来触发您的服务。

当然,有些情况下,你不想这样做"programmatically",那么你应该检查错误情况,从这个link http://androidxref.com/8.1.0_r33/xref/frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java#1275 (Line:1275 ),我发现错误(不确定这是否与您的系统版本相同)。

我们可以看到访问这个代码块的条件很少,我们一一分析,我们要做的就是让条件等于false

(r.intent.getFlags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0

表示如果我们不希望后台接收到intent,则条件为真,通常我们不添加此标志,因为我们希望后台接收广播,继续。

r.intent.getComponent() == null

在我们的任何情况下都不应该为空,继续。

r.intent.getPackage() == null

同上,继续

r.intent.getFlags()&Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0

这意味着我们不能有一个名为 Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND 的标志,我想我们可以试试这个,但是你会在 Intent class:

中看到这个
   /**
     * 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)

祝你好运:)

注意:此解决方案不会解析接收系统隐式广播到 运行 后台任务。

这是一个老问题,但我找到了适合我的解决方案。

如前所述here

Context-registered receivers receive broadcasts as long as their registering context is valid. For an example, if you register within an Activity context, you receive broadcasts as long as the activity is not destroyed. If you register with the Application context, you receive broadcasts as long as the app is running.

我不得不完全删除清单中的接收器声明并在运行时使用 应用程序上下文!

注册我的接收器
IntentFilter filter = new IntentFilter("owner.custom.broadcast");
getContext().getApplicationContext().registerReceiver(new MyReceiver(), filter);

然后

public class MyReceiver extends BroadcastReceiver
{
    @Override
    public void onReceive(Context context, Intent intent)
    {
        context.unregisterReceiver(this);
        // ....
    }
}