webentwicklung-frage-antwort-db.com.de

Hintergrundausführung darf nicht empfangen werden. Absicht Absicht BOOT_COMPLETED

Ich habe über Einschränkungen bei der Ausführung von Android Oreo im Hintergrund gelesen und besagt eindeutig, dass BOOT_COMPLETED broadcast nicht betroffen ist, aber ich kann nicht, dass es mit Android Oreo funktioniert.

Erstens kompiliere ich gegen SDK 27. Zweitens habe ich den Empfänger in der Manifestdatei deklariert:

    <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>

Dann gibt es noch die Implementierung des Empfängers, die auch so einfach sein kann:

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);
    }
}

Die onReceive-Methode wird nicht aufgerufen, und ich werde immer einen Logcat-Fehler auf Android-Oreo-Geräten/Emulator erhalten:

W/BroadcastQueue: Hintergrundausführung nicht zulässig: Empfangen von Absicht { act = Android.intent.action.BOOT_COMPLETED flg = 0x400010}

Beim Lesen anderer Antworten sagten sie, es gab einige Probleme bei der Registrierung expliziter Absichten im Manifest, aber dies ist nicht der Fall von BOOT_COMPLETED.

Weder dies hat geholfen, weil der Empfänger überhaupt nicht angerufen wird.

Broadcast-Intent zur Laufzeit registrieren, damit es funktioniert (auf dem Emulator, Abfeuern der Absicht von Adb-Shell), aber ich bin nicht sicher, ob dies der richtige Weg ist:

registerReceiver(new StartDetectionAtBoot(), new IntentFilter(Intent.ACTION_BOOT_COMPLETED));

Gibt es irgendwelche bekannten Fehler dabei?

8
fillobotto

Die Lösung war eine Kombination aus zwei Versuchen, die ich bereits gemacht hatte.

Zuerst musste ich einen Vordergrunddienst starten (selbst ein Dummy-Dienst wäre gut) mit einer Benachrichtigung: 

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);
    }
}

Innerhalb des Dienstes, den Sie starten, muss natürlich eine onCreate-Methode vorhanden sein, die eine Benachrichtigung erstellt und startForeground aufruft.

Zweitens hatte ich in Android Studio eine Cache-Ungültigerklärung durchgeführt und auch die Emulatorinstanz gelöscht. Dieser Teil der Lösung war notwendig für mich, da der erste Teil noch nicht funktionierte.

0
fillobotto

Die Selbstregistrierung Ihrer Empfänger in einem Code für die erforderlichen impliziten Absichten ist wirklich der richtige Weg, um diese Absichten zu empfangen. Dazu ist kein Dienst erforderlich (in den meisten Fällen siehe unten ...). Sie müssen jedoch Folgendes beachten, um beim Testen nicht verwechselt zu werden und die frühere Implementierung nicht zu unterbrechen:

  1. Die Selbstregistrierung sollte einmal pro Anwendungslauf ausgeführt werden. In Bezug auf Java/Kotlin-Anwendungsdaten: einmal pro statischem Feldleben. In einem statischen booleschen Feld sollten Sie also Folgendes wissen: Ob Sie sich selbst registrieren müssen (z. B. nach einem Neustart oder nachdem das Android-System Ihre App später beendet hat ...) oder nicht (ich zitiere Arbeitscode aus diesem Commit: 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;
    }
  1. Fügen Sie den Aufruf Ihrer registerReceivers-Methode an all möglichen Einstiegspunkten Ihrer Anwendung ein, um die Wahrscheinlichkeit zu erhöhen, dass die Empfänger registriert werden, selbst wenn Ihre Anwendung nur einmal von einem Android-System gestartet wurde, z.
    @Override
    public void onUpdate(Context baseContext, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        registerReceivers(baseContext);

        ...
    }
  1. Sie können Ihre Empfänger in der gleichen Weise wie in der Datei AndroidManifest.xml registrieren lassen (da dies für Android vor v.7 funktioniert ...). Beachten Sie jedoch, dass in logcat in diesem Fall immer noch "Hintergrundausführung nicht zulässig" angezeigt wird eine Referenz zu Ihren Empfängern. Dies bedeutet nur, dass die Registrierung über AndroidManifest.xml nicht funktioniert (wie bei Android 8+ erwartet), aber selbstregistrierte Empfänger sollten trotzdem aufgerufen werden!

  2. Wie oben erwähnt, ist das Starten des Vordergrunddiensts für ein leichtes Widget im Allgemeinen nicht erforderlich. Außerdem möchte ein Benutzer nicht ständig die Benachrichtigung sehen, dass Ihr "Widget" im Vordergrund ausgeführt wird (und daher ständig Ressourcen frisst). Der einzige Fall, in dem dies wirklich erforderlich sein kann, ist, wenn Android Ihre Anwendung zu oft beendet und die nach dem Neustart durchgeführte Selbstregistrierung löscht .. Ich denke, dass Ihre "Widget-Anwendung" so leicht wie möglich gemacht wird (so wenig wie möglich) Speicher und CPU-Ressourcen, wie möglich ...) ist der richtige Weg, um sicherzustellen, dass Ihre Widget-App nur in kritischen Fällen für Ihr Gerät beendet wird ... Vielleicht sollten Sie Ihre große App in zwei Teile aufteilen, um eine Widget-Art zu erstellen Launcher für die schwergewichtige App, die ab und zu funktionieren muss ...

0
yvolk