Essayer de démarrer un service au démarrage sur Android

332

J'ai essayé de démarrer un service lorsqu'un appareil démarre sur Android, mais je n'arrive pas à le faire fonctionner. J'ai regardé un certain nombre de liens en ligne, mais aucun code ne fonctionne. Suis-je en train d'oublier quelque chose?

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

BroadcastReceiver

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
la source
2
je ne sais pas ce que j'ai fait mais je pense que cela fonctionne maintenant, il pourrait s'agir de l'androïde: permission = "android.permission.RECEIVE_BOOT_COMPLETED" pour le récepteur
Alex
avez-vous vérifié le "_" supplémentaire dans <action android: name = "android.intent.action._BOOT_COMPLETED" />
OneWorld
L'export doit être vrai pour que le système puisse invoquer le récepteur, non? Ou est-ce vrai par défaut?
Eugen Pechanec
pour Oreo, regardez ici: stackoverflow.com/questions/44502229/…
Andy Weinstein

Réponses:

601

Les autres réponses semblent bonnes, mais je pensais que je résumerais tout en une réponse complète.

Vous avez besoin des éléments suivants dans votre AndroidManifest.xmldossier:

  1. Dans votre <manifest>élément:

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
  2. Dans votre <application>élément (assurez-vous d'utiliser un nom de classe [ou relatif] complet pour votre BroadcastReceiver):

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

    (vous n'avez pas besoin android:enabled, exportedetc., les attributs: les valeurs par défaut Android sont corrects)

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

De la question d'origine:

  • on ne sait pas si l' <receiver>élément était dans l' <application>élément
  • il n'est pas clair si le nom de classe complet (ou relatif) correct pour le a BroadcastReceiverété spécifié
  • il y avait une faute de frappe dans le <intent-filter>
Timo Bruck
la source
2
Cela semble bon. Je vais l'utiliser comme base, merci :). Pas de coche ni de votes positifs ni de réponse malheureusement :(. Quelqu'un le vérifie-t-il?
Nanne
51
Juste un complément: assurez-vous que votre application est installée dans la mémoire interne <manifest xmlns: android = "..." package = "..." android: installLocation = "internalOnly">
Bao Le
2
Dans Android Jellybean 4.2.2 dans la balise <receiver>, j'ai dû utiliser le nom relatif de la classe au lieu du nom complet pour que le service démarre, comme indiqué dans stackoverflow.com/questions/16671619/…
Piovezan
6
Si le récepteur est utilisé pour différentes choses: <br> if ("android.intent.action.BOOT_COMPLETED" .equals (intent.getAction ())) {Intent serviceIntent = new Intent (context, Service_Location.class); // i.putExtra ("KEY1", "Valeur à utiliser par le service"); context.startService (serviceIntent); }
Gunnar Bernstein
2
Vous devez étendre developer.android.com/reference/android/support/v4/content/… à la place. Il s'agit d'une aide pour le modèle courant d'implémentation d'un BroadcastReceiver qui reçoit un événement de réveil de périphérique puis transmet le travail à un service, tout en garantissant que le périphérique ne se rend pas en veille pendant la transition. Cette classe s'occupe de créer et de gérer un verrouillage de réveil partiel pour vous; vous devez demander l'autorisation WAKE_LOCK pour l'utiliser.
Damian
84

Comme information supplémentaire: BOOT_COMPLETE est envoyé aux applications avant le montage du stockage externe. Donc, si l'application est installée sur un stockage externe, elle ne recevra pas de message de diffusion BOOT_COMPLETE.

Plus de détails ici dans la section Récepteurs de diffusion écoutant le "démarrage terminé"

inazaruk
la source
Pour éviter le problème ci-dessus, le développeur peut définir "android: installLocation =" internalOnly "dans le manifeste d'une application. Est-ce une mauvaise idée? Pour une application pour smartphone, si 99,9% (à mon avis) de tous les utilisateurs installent l'application normalement , en utilisant le stockage interne plutôt que le stockage externe, alors il semble que l'ajout "internalOnly" au manifeste serait parfait. J'apprécierais toutes vos pensées ou idées à ce sujet.
AJW
69

Comment démarrer le service au démarrage de l'appareil (application d'exécution automatique, etc.)

Pour commencer: depuis la version Android 3.1+, vous ne recevez pas BOOT_COMPLETE si l'utilisateur n'a jamais démarré votre application au moins une fois ou si l'utilisateur a "forcé la fermeture" de l'application. Cela a été fait pour empêcher les logiciels malveillants d'enregistrer automatiquement le service. Ce trou de sécurité a été fermé dans les nouvelles versions d'Android.

Solution:

Créez une application avec une activité. Lorsque l'utilisateur l'exécute une fois que l'application peut recevoir un message de diffusion BOOT_COMPLETE.

Pour le second: BOOT_COMPLETE est envoyé avant le montage du stockage externe. Si l'application est installée sur un stockage externe, elle ne recevra pas de message de diffusion BOOT_COMPLETE.

Dans ce cas, il existe deux solutions:

  1. Installez votre application sur le stockage interne
  2. Installez une autre petite application dans le stockage interne. Cette application reçoit BOOT_COMPLETE et exécute la deuxième application sur un stockage externe.

Si votre application est déjà installée dans le stockage interne, le code ci-dessous peut vous aider à comprendre comment démarrer le service au démarrage de l'appareil.


Dans Manifest.xml

Autorisation:

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

Enregistrez votre récepteur BOOT_COMPLETED:

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

Enregistrez votre service:

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

Dans le récepteur 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);

    }

 }

Pour HTC, vous devrez peut-être également ajouter dans Manifest ce code si l'appareil n'attrape pas RECEIVE_BOOT_COMPLETED:

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

Le récepteur ressemble maintenant à ceci:

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

Comment tester BOOT_COMPLETED sans redémarrer l'émulateur ni l'appareil réel? C'est facile. Essaye ça:

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

Comment obtenir l'identifiant de l'appareil? Obtenez la liste des appareils connectés avec des identifiants:

adb devices

adb dans ADT par défaut, vous pouvez trouver dans:

adt-installation-dir/sdk/platform-tools

Prendre plaisir! )

user3439968
la source
Votre premier paragraphe était capital. Je n'ai pas pu le faire fonctionner dans mon débogueur.
estornes
34

De même que

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

utiliser aussi,

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

Les appareils HTC ne semblent pas attraper BOOT_COMPLETED

Tony
la source
Besoin d'ajouter quelque chose de similaire dans les autorisations pour les appareils HTC?
Nanda
2
Cela pourrait être utile dans certaines circonstances, mais je comprends que le HTC Fast Boot est une forme d'hibernation où l'état du système est enregistré dans le système de fichiers, et android.intent.action.QUICKBOOT_POWERONn'est envoyé que lors de la restauration à partir du démarrage rapide. Cela signifie qu'il n'est pas nécessaire de faire des choses comme la réinitialisation des alarmes lors de la récupération à partir de Fast Boot car elles sont préservées. Par conséquent, il ne sera nécessaire d'utiliser que <action android:name="android.intent.action.QUICKBOOT_POWERON" />si vous voulez faire quelque chose lorsque l'utilisateur pense que l'appareil a démarré.
HexAndBugs
2
Du point de vue d'un développeur d'applications, nous ne devrions jamais l'utiliser, si le comportement existe uniquement sur les appareils HTC. Parce que BOOT_COMPLETED est, selon la documentation, toujours envoyé lorsque l'appareil s'allume. Un autre fabricant pourrait proposer une autre méthode de démarrage rapide et nous finirions par salir notre code avec les spécifications de chacun.
Subin Sebastian
@HexAndBugs Avez-vous pu confirmer que Fast Boot est une forme d'hibernation où l'état du système est enregistré dans le système de fichiers? Je veux être en mesure de réinitialiser les alarmes utilisées pour les notifications futures après un démarrage rapide si l'état du système n'est pas enregistré ... veuillez en informer.
AJW
20

notez qu'au début de la question, il y a une faute de frappe:

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

au lieu de :

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

un petit "_" et tous ces ennuis :)

Evgeny Erlihman
la source
13

Je viens de découvrir que cela pourrait être dû à l' Fast Bootoption dans Settings>Power

Lorsque cette option est désactivée, mon application reçoit cette diffusion, mais pas autrement.

D'ailleurs, je Android 2.3.3le HTC Incredible S.

J'espère que ça aide.

Omer Akhter
la source
Cause certainement possible du problème. Observé également sur HTC Desire C sous Android 4.0.3.
Zelimir
7

Après avoir essayé toutes les réponses et astuces mentionnées, je trouve enfin pourquoi le code ne fonctionne pas sur mon téléphone. Certains téléphones Android comme «Huawei Honor 3C Android 4.2.2 » ont un menu Statup Manager dans leurs paramètres et votre application doit être cochée dans la liste. :)

Amir
la source
5

J'ai une <category>étiquette supplémentaire , je ne sais pas si cela fait une différence.

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

Avez-vous essayé de supprimer la clause if "android.intent.action.BOOT_COMPLETED".equals(intent.getAction(), car le destinataire ne reçoit probablement cette intention de toute façon?

pseudo
la source
essayé cela et cela n'a pas fonctionné btw j'ai oublié de mentionner que j'ai également le <uses-permission android: name = "android.permission.RECEIVE_BOOT_COMPLETED" />
Alex
2
juste au cas où: l'ajout de android.intent.category.HOME à n'importe quelle balise dans AndroidManifest entraînera l'application Samsung Galaxy Tab en mode de compatibilité, même après avoir utilisé le hack pour désactiver le mode de compatibilité. Je ne sais pas si c'est la même chose pour les autres onglets. je recommande de ne pas définir la catégorie HOME du tout. c'est inutile.
moonlightcheese
3

Avant de monter le stockage externe, BOOT_COMPLETE est envoyé execute.si votre application est installée sur un stockage externe, elle ne recevra pas le message de diffusion BOOT_COMPLETE. Pour éviter cela, vous pouvez installer votre application dans le stockage interne. vous pouvez le faire en ajoutant simplement cette ligne dans menifest.xml

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

Certains appareils HTC peuvent activer une fonction de «démarrage rapide» qui ressemble plus à une mise en veille prolongée et non à un véritable redémarrage et ne devrait donc pas donner l'intention BOOT_COMPLETE. Pour récupérer cela, vous pouvez ajouter ce filtre d'intention à l'intérieur de votre récepteur:

            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.QUICKBOOT_POWERON" />
            </intent-filter>
Md. Sajedul Karim
la source
Comme vous le suggérez, pour éviter le problème ci-dessus, le développeur pourrait définir "android: installLocation =" internalOnly "dans le manifeste pour une application. Est-ce une mauvaise idée? Pour une application pour smartphone, si 99,9% (je suppose) de tous les utilisateurs installer l'application normalement, en utilisant le stockage interne plutôt que le stockage externe, alors il semble que l'ajout "internalOnly" au manifeste serait parfait. J'apprécierais toutes les pensées ou idées que vous avez à ce sujet. - AJW
AJW
3

C'est ce que j'ai fait

1. J'ai fait la classe Receiver

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. dans le manifeste

<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. et après TOUT ce dont vous avez besoin pour "régler" le récepteur dans votre MainActivity, il peut être à l'intérieur du 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);
...

la dernière étape que j'ai apprise d'ApiDemos

San Juan
la source
2

Si vous utilisez Android Studio et que vous aimez beaucoup la saisie semi-automatique, je dois vous informer que j'utilise Android Studio v 1.1.0 et j'ai utilisé la saisie semi-automatique pour l'autorisation suivante

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

Et Android Studio a complété automatiquement RECEIVE_BOOT_COMPLETEDtout en minuscules comme receive_boot_completedet j'ai continué à m'arracher les cheveux parce que j'avais déjà coché ma liste de contrôle pour les choses à faire pour démarrer le service au démarrage. Je viens de confirmer à nouveau

Android Studio NE REMPLIT PAS automatiquement cette autorisation en minuscules.

Haroon Dilshad
la source
2

Comme l'a commenté @Damian, toutes les réponses de ce fil le font mal. Si vous le faites manuellement comme cela, vous risquez que votre service soit arrêté au milieu de l'appareil en veille. Vous devez d'abord obtenir un verrouillage de réveil. Heureusement, la bibliothèque de support nous donne une classe pour ce faire:

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

puis, dans votre Service, assurez-vous de libérer le verrouillage de réveil:

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

N'oubliez pas d'ajouter la permission WAKE_LOCK à votre mainfest:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
phreakhead
la source
Petite question, j'ai un doute. Si mon service de est un service et non IntentService je ne peux pas utiliser de cette façon, car onHandleIntend méthode ne peut pas être prioritaire dans un langage simple service ?
paolo2988
J'ai le même problème. Ça vous dérange de m'aider? Merci! stackoverflow.com/questions/35373525/starting-my-service
Ruchir Baronia
Peut-être utiliser onNewIntent()? Ou vous pouvez regarder la source d'IntentService et voir ce que vous devez faire pour que votre service le fasse correspondre ...
phreakhead
1

En fait, j'ai eu ce problème il n'y a pas longtemps, et c'est vraiment très facile à résoudre, vous ne faites rien de mal si vous configurez l' "android.intent.action.BOOT_COMPLETED"autorisation et le filtre d'intention.

Sachez que si vous sur Android 4.X, vous devez exécuter l'écouteur de diffusion avant de démarrer le service au démarrage, cela signifie que vous devez d'abord ajouter une activité, une fois votre récepteur de diffusion en cours d'exécution, votre application devrait fonctionner comme prévu, Cependant, sur Android 4.X, je n'ai pas trouvé de moyen de démarrer le service au démarrage sans aucune activité, je pense que Google l'a fait pour des raisons de sécurité.

David Hx
la source
0

J'ai fait face à ce problème si je laisse le constructeur vide dans la classe récepteur. Après la suppression du constructeur vide, les méthos de réception ont commencé à fonctionner correctement.

redrom
la source