后台执行不允许接收意图BOOT_COMPLETED

fil*_*tto 13 android broadcastreceiver android-background android-8.0-oreo

我已经阅读了有关Android Oreo背景执行限制的内容,并且明确指出BOOT_COMPLETED广播不会受到影响,但我无法让它在Android Oreo上运行.

首先,我正在编译SDK 27.其次,我在清单文件中声明了接收器:

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <receiver
        android:name="helpers.StartDetectionAtBoot"
        android:label="StartDetectionAtBoot"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <category android:name="android.intent.category.DEFAULT"/>

            <action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>

            <action android:name="android.intent.action.BOOT_COMPLETED"/>
            <action android:name="android.intent.action.QUICKBOOT_POWERON"/>
            <!--For HTC devices-->
            <action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
            <!--For MIUI devices-->
            <action android:name="android.intent.action.REBOOT"/>
        </intent-filter>
    </receiver>
Run Code Online (Sandbox Code Playgroud)

然后就是接收器的实现,它也可以很简单:

public class StartDetectionAtBoot extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i("test", "test");

        Intent intent0 = new Intent( context, ActivityRecognitionService.class );
        PendingIntent pendingIntent = PendingIntent.getService(context, 111, intent0, PendingIntent.FLAG_UPDATE_CURRENT);
        ActivityRecognitionClient activityRecognitionClient = ActivityRecognition.getClient(context);
        activityRecognitionClient.requestActivityUpdates(5000, pendingIntent);
    }
}
Run Code Online (Sandbox Code Playgroud)

onReceive 方法未被调用,我将永远在Android Oreo设备/模拟器上获得logcat错误:

W/BroadcastQueue:不允许后台执行:接收Intent {act = android.intent.action.BOOT_COMPLETED flg = 0x400010}

阅读其他答案,他们说在清单中注册显式意图时存在一些问题,但事实并非如此BOOT_COMPLETED.

无论这种帮助,因为接收方不叫的.

在运行时注册广播意图,让它工作(在模拟器上,从adb shell激发意图),但我不确定这是正确的方法:

registerReceiver(new StartDetectionAtBoot(), new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
Run Code Online (Sandbox Code Playgroud)

这有什么已知的错误吗?

yvo*_*olk 7

在所需的隐式意图的代码中自行注册您的接收器确实是开始接收该意图的正确方法。不需要为此提供服务(在大多数情况下,请参见下文...)。但是您需要注意以下几点,以免在测试过程中混淆,也不要破坏早期的实现:

  1. 每次应用程序运行时应进行一次自注册。在 Java / Kotlin 应用程序数据方面:每个静态字段生命一次。因此,一个静态布尔字段应该让您知道:是否需要自行注册(例如,在重新启动后或 Android 系统稍后杀死您的应用程序后...)(我引用了此提交中的工作代码:https://github .com/andstatus/todoagenda/commit/74ffc1495f2c4bebe5c43aab13389ea0ea821fde):
    private static volatile boolean receiversRegistered = false;

    private static void registerReceivers(Context contextIn) {
        if (receiversRegistered) return;

        Context context = contextIn.getApplicationContext();
        EnvironmentChangedReceiver receiver = new EnvironmentChangedReceiver();

        IntentFilter providerChanged = new IntentFilter();
        providerChanged.addAction("android.intent.action.PROVIDER_CHANGED");
        providerChanged.addDataScheme("content");
        providerChanged.addDataAuthority("com.android.calendar", null);
        context.registerReceiver(receiver, providerChanged);

        IntentFilter userPresent = new IntentFilter();
        userPresent.addAction("android.intent.action.USER_PRESENT");
        context.registerReceiver(receiver, userPresent);

        Log.i(EventAppWidgetProvider.class.getName(), "Registered receivers from " + contextIn.getClass().getName());
        receiversRegistered = true;
    }
Run Code Online (Sandbox Code Playgroud)
  1. 将 registerReceivers 方法的调用插入到应用程序的所有可能入口点,以最大限度地提高接收器注册的机会,即使您的应用程序仅由 Android 系统启动一次,例如:
    @Override
    public void onUpdate(Context baseContext, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        registerReceivers(baseContext);

        ...
    }
Run Code Online (Sandbox Code Playgroud)
  1. 您可以将接收器注册到 AndroidManifest.xml 文件中的相同意图(因为这适用于 v.7 之前的 Android ......),但请注意,在这种情况下,在 logcat 中您仍然会看到“不允许后台执行”对您的接收器的引用。这仅意味着通过 AndroidManifest.xml 进行注册不起作用(正如 Android 8+ 所预期的那样),但无论如何都应该调用自注册接收器!

  2. 正如我上面提到的,对于轻量级小部件,通常不需要启动前台服务。此外,用户不会喜欢不断看到您的“小部件”在前台运行的通知(因此不断地消耗资源)。唯一的情况,当这可能真的需要时,是当 Android 过于频繁地杀死您的应用程序,从而删除重新启动后完成的自注册。我认为使您的“小部件应用程序”尽可能轻巧(需要尽可能少的内存和 CPU 资源......)是确保您的小部件应用程序仅在您的设备的关键情况下才会被终止的正确方法。 . 也许你应该把你的大应用一分为二,为需要不时工作的重量级应用制作一个小部件类型的启动器......


小智 6

W/BroadcastQueue:不允许后台执行:receiving Intent { act=android.intent.action.BOOT_COMPLETED **flg=0x400010** }

您从 adb shell 测试意图,可能与Android 系统在启动期间发送的am broadcast -a android.intent.action.BOOT_COMPLETED 意图flg=0x400010不同。flg=0x9000010

您可以在 找到标志定义frameworks/base/core/java/android/content/Intent.java。flg=0x400010没有一点FLAG_RECEIVER_FOREGROUND = 0x10000000。

所以,如果你想从 adb shell 测试意图,你可以使用 am broadcast -a android.intent.action.BOOT_COMPLETED *--receiver-include-background.*


fil*_*tto 3

该解决方案是我已经做过的两次尝试的组合。

首先,我必须启动一个带有粘性通知的前台服务(即使是虚拟服务也很好):

public class StartDetectionAtBoot extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            Intent intent1 = new Intent(context.getApplicationContext(), DummyService.class);
            context.startForegroundService(intent1);
        }

        Intent intent0 = new Intent( context, ActivityRecognitionService.class );
        PendingIntent pendingIntent = PendingIntent.getService(context, 111, intent0, PendingIntent.FLAG_UPDATE_CURRENT);
        ActivityRecognitionClient activityRecognitionClient = ActivityRecognition.getClient(context);
        activityRecognitionClient.requestActivityUpdates(5000, pendingIntent);
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,在您启动的服务内部必须有一个onCreate创建通知并调用的方法startForeground。

其次,我在 Android Studio 中进行了缓存失效,并且还擦除了模拟器实例。解决方案的这一部分对我来说是必要的,因为第一部分仍然不起作用。