Versuch, einen Dienst beim Booten unter Android zu starten

332

Ich habe versucht, einen Dienst zu starten, wenn ein Gerät auf Android startet, aber ich kann es nicht zum Laufen bringen. Ich habe mir eine Reihe von Links online angesehen, aber keiner der Codes funktioniert. Vergesse ich etwas?

AndroidManifest.xml

<receiver
    android:name=".StartServiceAtBootReceiver"
    android:enabled="true"
    android:exported="false"
    android:label="StartServiceAtBootReceiver" >
    <intent-filter>
        <action android:name="android.intent.action._BOOT_COMPLETED" />
    </intent-filter>
</receiver>

<service
    android:name="com.test.RunService"
    android:enabled="true" />

Rundfunkempfänger

public void onReceive(Context context, Intent intent) {
    if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
        Intent serviceLauncher = new Intent(context, RunService.class);
        context.startService(serviceLauncher);
        Log.v("TEST", "Service loaded at start");
    }
}
Alex
quelle
2
Ich weiß nicht, was ich getan habe, aber ich denke, es funktioniert jetzt, es könnte der Android gewesen sein: Erlaubnis = "android.permission.RECEIVE_BOOT_COMPLETED" für den Empfänger
Alex
Haben Sie das zusätzliche "_" in <action android: name = "android.intent.action._BOOT_COMPLETED" />
OneWorld
Exportiert muss wahr sein, damit das System den Empfänger aufrufen kann, nein? Oder ist es standardmäßig wahr?
Eugen Pechanec
Oreo finden Sie hier: stackoverflow.com/questions/44502229/…
Andy Weinstein

Antworten:

601

Die anderen Antworten sehen gut aus, aber ich dachte, ich würde alles in einer vollständigen Antwort zusammenfassen.

Sie benötigen Folgendes in Ihrer AndroidManifest.xmlDatei:

  1. In deinem <manifest>Element:

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
  2. In Ihrem <application>Element (stellen Sie sicher, dass Sie einen vollständig qualifizierten [oder relativen] Klassennamen für Ihr Element verwenden BroadcastReceiver):

    <receiver android:name="com.example.MyBroadcastReceiver">  
        <intent-filter>  
            <action android:name="android.intent.action.BOOT_COMPLETED" />  
        </intent-filter>  
    </receiver>

    (Sie brauchen nicht die android:enabled, exportedetc., Attribute: die Android Vorgaben korrekt sind)

    In MyBroadcastReceiver.java:

    package com.example;
    
    public class MyBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Intent startServiceIntent = new Intent(context, MyService.class);
            context.startService(startServiceIntent);
        }
    }

Aus der ursprünglichen Frage:

  • Es ist nicht klar, ob sich das <receiver>Element im <application>Element befand
  • Es ist nicht klar, ob der richtige vollqualifizierte (oder relative) Klassenname für BroadcastReceiverangegeben wurde
  • Es gab einen Tippfehler in der <intent-filter>
Timo Bruck
quelle
2
Das sieht gut aus. Ich werde dies als Grundlage verwenden, danke :). Kein Häkchen oder Upvotes oder Antwort leider :(. Hat jemand dies überprüft?
Nanne
51
Nur eine Ergänzung: Stellen Sie sicher, dass Ihre App im internen Speicher installiert ist <manifest xmlns: android = "..." package = "..." android: installLocation = "internalOnly">
Bao Le
2
In Android Jellybean 4.2.2 im <receiver> -Tag musste ich den relativen Namen der Klasse anstelle des vollständig qualifizierten Namens verwenden, damit der Dienst gestartet werden kann, wie unter stackoverflow.com/questions/16671619/…
Piovezan
6
Wenn der Empfänger für verschiedene Zwecke verwendet wird: <br> if ("android.intent.action.BOOT_COMPLETED" .equals (intent.getAction ())) {Intent serviceIntent = new Intent (Kontext, Service_Location.class); // i.putExtra ("KEY1", "Vom Dienst zu verwendender Wert"); context.startService (serviceIntent); }
Gunnar Bernstein
2
Sie sollten stattdessen developer.android.com/reference/android/support/v4/content/… erweitern . Es ist ein Hilfsprogramm für das allgemeine Muster der Implementierung eines BroadcastReceivers, der ein Geräteweckereignis empfängt und die Arbeit dann an einen Dienst weiterleitet, während sichergestellt wird, dass das Gerät während des Übergangs nicht wieder in den Ruhezustand wechselt. Diese Klasse kümmert sich um das Erstellen und Verwalten einer partiellen Wecksperre für Sie. Sie müssen die WAKE_LOCK-Berechtigung anfordern, um sie verwenden zu können.
Damian
84

Als zusätzliche Information: BOOT_COMPLETE wird an Anwendungen gesendet, bevor der externe Speicher bereitgestellt wird . Wenn die Anwendung auf einem externen Speicher installiert ist, empfängt sie keine BOOT_COMPLETE-Broadcast-Nachricht.

Weitere Details finden Sie hier im Abschnitt Rundfunkempfänger, die auf "Start abgeschlossen" warten.

inazaruk
quelle
Um das oben genannte Problem zu vermeiden, könnte der Entwickler "android: installLocation =" internalOnly "im Manifest für eine App festlegen. Ist das eine schlechte Idee? Für eine Smartphone-App, wenn 99,9% (meine Vermutung) aller Benutzer die App normal installieren Wenn Sie internen Speicher anstelle von externem Speicher verwenden, scheint der Zusatz "internalOnly" zum Manifest in Ordnung zu sein. Ich würde mich über
Ihre
69

So starten Sie den Dienst beim Gerätestart (Autorun-App usw.)

Zum einen: Seit der Version Android 3.1+ erhalten Sie BOOT_COMPLETE nicht mehr, wenn der Benutzer Ihre App nie mindestens einmal gestartet hat oder der Benutzer die Anwendung "erzwingen". Dies wurde durchgeführt, um zu verhindern, dass Malware den Dienst automatisch registriert. Diese Sicherheitslücke wurde in neueren Versionen von Android geschlossen.

Lösung:

App mit Aktivität erstellen. Wenn der Benutzer es einmal ausführt, kann die App die Broadcast-Nachricht BOOT_COMPLETE empfangen.

Zum zweiten: BOOT_COMPLETE wird gesendet, bevor der externe Speicher bereitgestellt wird. Wenn die App auf einem externen Speicher installiert ist, empfängt sie keine BOOT_COMPLETE-Broadcast-Nachricht.

In diesem Fall gibt es zwei Lösungen:

  1. Installieren Sie Ihre App im internen Speicher
  2. Installieren Sie eine weitere kleine App im internen Speicher. Diese App empfängt BOOT_COMPLETE und führt die zweite App auf einem externen Speicher aus.

Wenn Ihre App bereits im internen Speicher installiert ist, kann Ihnen der folgende Code helfen, den Dienst beim Gerätestart zu starten.


In Manifest.xml

Genehmigung:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

Registrieren Sie Ihren BOOT_COMPLETED-Empfänger:

<receiver android:name="org.yourapp.OnBoot">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
    </intent-filter>
</receiver>

Registrieren Sie Ihren Service:

<service android:name="org.yourapp.YourCoolService" />

Im Empfänger OnBoot.java:

public class OnBoot extends BroadcastReceiver
{

    @Override
    public void onReceive(Context context, Intent intent) 
    {
        // Create Intent
        Intent serviceIntent = new Intent(context, YourCoolService.class);
        // Start service
        context.startService(serviceIntent);

    }

 }

Für HTC müssen Sie diesen Code möglicherweise auch in Manifest hinzufügen, wenn das Gerät RECEIVE_BOOT_COMPLETED nicht abfängt:

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

Der Empfänger sieht jetzt so aus:

<receiver android:name="org.yourapp.OnBoot">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
        <action android:name="android.intent.action.QUICKBOOT_POWERON" />
    </intent-filter>
</receiver>

Wie kann man BOOT_COMPLETED testen, ohne den Emulator oder das reale Gerät neu zu starten? Es ist einfach. Versuche dies:

adb -s device-or-emulator-id shell am broadcast -a android.intent.action.BOOT_COMPLETED

Wie erhalte ich die Geräte-ID? Liste der verbundenen Geräte mit IDs abrufen:

adb devices

adb in ADT finden Sie standardmäßig in:

adt-installation-dir/sdk/platform-tools

Genießen! )

user3439968
quelle
Ihr erster Absatz war Kapital. Ich konnte es in meinem Debugger nicht zum Laufen bringen.
estornes
34

Zusammen mit

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

auch verwenden,

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

HTC-Geräte scheinen BOOT_COMPLETED nicht zu fangen

Tony
quelle
Müssen Sie ähnliche Berechtigungen für HTC-Geräte hinzufügen?
Nanda
2
Dies kann unter bestimmten Umständen nützlich sein, aber ich verstehe, dass das HTC Fast Boot eine Form des Ruhezustands ist, bei dem der Systemstatus im Dateisystem gespeichert wird und der android.intent.action.QUICKBOOT_POWERONnur beim Wiederherstellen vom Fast Boot gesendet wird. Dies bedeutet, dass beim Wiederherstellen von Fast Boot keine Alarme zurückgesetzt werden müssen, da diese beibehalten werden. Daher ist die Verwendung nur erforderlich, <action android:name="android.intent.action.QUICKBOOT_POWERON" />wenn Sie etwas tun möchten, wenn der Benutzer der Meinung ist, dass das Gerät gestartet wurde.
HexAndBugs
2
Aus Sicht eines App-Entwicklers sollten wir dies niemals verwenden, wenn das Verhalten nur auf HTC-Geräten vorliegt. Weil BOOT_COMPLETED gemäß der Dokumentation immer gesendet wird, wenn das Gerät eingeschaltet wird. Ein anderer Hersteller könnte sich eine andere Methode zum schnellen Booten einfallen lassen, und am Ende würden wir unseren Code mit den Spezifikationen jedes Einzelnen durcheinander bringen.
Subin Sebastian
@HexAndBugs Konnten Sie bestätigen, dass Fast Boot eine Form des Ruhezustands ist, bei dem der Systemstatus im Dateisystem gespeichert wird? Ich möchte in der Lage sein, Alarme zurückzusetzen, die für zukünftige Benachrichtigungen nach einem Schnellstart verwendet werden, wenn der Systemstatus nicht gespeichert ist. Bitte geben Sie an.
AJW
20

Beachten Sie, dass am Anfang der Frage ein Tippfehler vorliegt:

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

Anstatt von :

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

ein kleines "_" und all diese Probleme :)

Evgeny Erlihman
quelle
13

Ich habe gerade herausgefunden, dass es an der Fast BootOption in Settings> liegen könntePower

Wenn ich diese Option deaktiviert habe, empfängt meine Anwendung diese Sendung, jedoch nicht anders.

Übrigens habe ich Android 2.3.3weiter HTC Incredible S.

Ich hoffe es hilft.

Omer Akhter
quelle
Definitiv mögliche Ursache des Problems. Beobachtet auch auf dem HTC Desire C mit Android 4.0.3.
Zelimir
7

Nachdem ich alle genannten Antworten und Tricks ausprobiert habe, finde ich endlich heraus, warum der Code in meinem Telefon nicht funktioniert. Einige Android-Handys wie "Huawei Honor 3C Android 4.2.2 " haben ein Statup Manager- Menü in ihren Einstellungen und Ihre App muss in der Liste überprüft werden. :) :)

Amir
quelle
5

Ich habe einen zusätzlichen <category>Tag, weiß nicht, ob das einen Unterschied macht.

<receiver android:name="BootIntentReceiver">  
        <intent-filter>  
            <action android:name="android.intent.action.BOOT_COMPLETED" />  
            <category android:name="android.intent.category.HOME" />  
        </intent-filter>  
</receiver>

Haben Sie versucht, die if-Klausel wegzulassen "android.intent.action.BOOT_COMPLETED".equals(intent.getAction(), da der Empfänger diese Absicht wahrscheinlich sowieso nur erhält?

Nick
quelle
versuchte dies und es funktionierte übrigens nicht Ich habe vergessen zu erwähnen, dass ich auch die <Verwendungsberechtigung android: name = "android.permission.RECEIVE_BOOT_COMPLETED" />
Alex
2
Nur für den Fall: Wenn Sie android.intent.category.HOME zu einem Tag im AndroidManifest hinzufügen, führt das Samsung Galaxy Tab die App im Kompatibilitätsmodus aus, auch nachdem der Hack den Kompatibilitätsmodus deaktiviert hat. Ich bin mir nicht sicher, ob dies für andere Registerkarten gleich ist. Ich empfehle, die Kategorie HOME überhaupt nicht einzustellen. es ist unnötig.
Moonlightcheese
3

Vor dem Mounten des externen Speichers wird BOOT_COMPLETE ausgeführt. Wenn Ihre App auf einem externen Speicher installiert ist, wird keine BOOT_COMPLETE-Broadcast-Nachricht empfangen. Um dies zu verhindern, können Sie Ihre Anwendung im internen Speicher installieren. Sie können dies tun, indem Sie diese Zeile in menifest.xml hinzufügen

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:installLocation="internalOnly"
... >

Einige HTC-Geräte können eine "Schnellstart" -Funktion aktivieren, die eher einem tiefen Ruhezustand und keinem echten Neustart ähnelt und daher nicht die Absicht BOOT_COMPLETE geben sollte. Um dies wiederherzustellen, können Sie diesen Absichtsfilter in Ihrem Empfänger hinzufügen:

            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.QUICKBOOT_POWERON" />
            </intent-filter>
Md. Sajedul Karim
quelle
Um das oben genannte Problem zu vermeiden, könnte der Entwickler "android: installLocation =" internalOnly "im Manifest für eine App festlegen. Ist das eine schlechte Idee? Für eine Smartphone-App, wenn 99,9% (meine Vermutung) aller Benutzer Installieren Sie die App normalerweise, indem Sie internen Speicher anstelle von externem Speicher verwenden. Dann scheint es, als wäre die Ergänzung zu "internalOnly" zum Manifest in Ordnung. Ich würde mich über Ihre Gedanken oder Ideen zu diesem Thema freuen. - AJW
AJW
3

Das habe ich getan

1. Ich habe die Empfängerklasse gemacht

public class BootReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //whatever you want to do on boot
       Intent serviceIntent = new Intent(context, YourService.class);
       context.startService(serviceIntent);
    }
}

2.in dem Manifest

<manifest...>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <application...>
        <receiver android:name=".BootReceiver" android:enabled="true" android:exported="false">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
    ...

3.und nach ALLEN MÜSSEN Sie den Empfänger in Ihrer MainActivity "einstellen", befindet er sich möglicherweise im onCreate

...
 final ComponentName onBootReceiver = new ComponentName(getApplication().getPackageName(), BootReceiver.class.getName());
        if(getPackageManager().getComponentEnabledSetting(onBootReceiver) != PackageManager.COMPONENT_ENABLED_STATE_ENABLED)
        getPackageManager().setComponentEnabledSetting(onBootReceiver,PackageManager.COMPONENT_ENABLED_STATE_ENABLED,PackageManager.DONT_KILL_APP);
...

Der letzte Schritt, den ich von ApiDemos gelernt habe

San Juan
quelle
2

Wenn Sie Android Studio verwenden und die automatische Vervollständigung sehr mögen, muss ich Sie informieren. Ich verwende Android Studio v 1.1.0 und habe die automatische Vervollständigung für die folgende Berechtigung verwendet

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

Und Android Studio wurde automatisch RECEIVE_BOOT_COMPLETEDin Kleinbuchstaben ausgefüllt, receive_boot_completedund ich zog mir immer wieder die Haare aus, weil ich bereits meine Checkliste für Aktivitäten zum Starten des Dienstes beim Booten angekreuzt hatte. Ich habe es gerade noch einmal bestätigt

Android Studio vervollständigt diese Berechtigung automatisch in Kleinbuchstaben.

Haroon Dilshad
quelle
2

Wie @Damian kommentierte, machen alle Antworten in diesem Thread es falsch. Wenn Sie dies manuell tun, besteht die Gefahr, dass Ihr Dienst in der Mitte gestoppt wird, wenn das Gerät in den Ruhezustand wechselt. Sie müssen zuerst eine Wecksperre erhalten. Glücklicherweise gibt uns die Support-Bibliothek eine Klasse , um dies zu tun:

public class SimpleWakefulReceiver extends WakefulBroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // This is the Intent to deliver to our service.
        Intent service = new Intent(context, SimpleWakefulService.class);

        // Start the service, keeping the device awake while it is launching.
        Log.i("SimpleWakefulReceiver", "Starting service @ " + SystemClock.elapsedRealtime());
        startWakefulService(context, service);
    }
}

Stellen Sie dann in Ihrem Dienst sicher, dass die Wecksperre aufgehoben wird:

    @Override
    protected void onHandleIntent(Intent intent) {
        // At this point SimpleWakefulReceiver is still holding a wake lock
        // for us.  We can do whatever we need to here and then tell it that
        // it can release the wakelock.

...
        Log.i("SimpleWakefulReceiver", "Completed service @ " + SystemClock.elapsedRealtime());
        SimpleWakefulReceiver.completeWakefulIntent(intent);
    }

Vergiss nicht, die WAKE_LOCK-Berechtigung zu deinem Hauptfest hinzuzufügen:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
Phreakhead
quelle
Kleine Frage, ich habe Zweifel. Wenn mein Dienst ein Dienst und kein IntentService ist, kann ich diese Methode nicht verwenden, da die onHandleIntend- Methode im einfachen Dienst nicht überschrieben werden kann .
paolo2988
Ich habe das gleiche Problem. Hast du etwas dagegen, mir zu helfen? Vielen Dank! stackoverflow.com/questions/35373525/starting-my-service
Ruchir Baronia
Vielleicht verwenden onNewIntent()? Oder Sie können sich die Quelle für IntentService ansehen und sehen, was Sie tun müssen, damit Ihr Service übereinstimmt ...
Phreakhead
1

Tatsächlich bin ich vor nicht allzu langer Zeit in dieses Problem geraten, und es ist wirklich sehr einfach zu beheben. Sie machen eigentlich nichts falsch, wenn Sie die "android.intent.action.BOOT_COMPLETED"Berechtigungs- und Absichtsfilter einrichten.

Beachten Sie, dass Sie unter Android 4.X den Broadcast-Listener ausführen müssen, bevor Sie den Dienst beim Booten starten. Dies bedeutet, dass Sie zuerst eine Aktivität hinzufügen müssen, sobald Ihr Broadcast-Empfänger ausgeführt wird, sollte Ihre App wie erwartet funktionieren. Unter Android 4.X habe ich jedoch keine Möglichkeit gefunden, den Dienst beim Booten ohne Aktivität zu starten. Ich denke, Google hat dies aus Sicherheitsgründen getan.

David Hx
quelle
0

Ich war mit diesem Problem konfrontiert, wenn ich den leeren Konstruktor in der Empfängerklasse belasse. Nach dem Entfernen des leeren Konstruktors funktionierte onRreceive Methos einwandfrei.

redrom
quelle