Tentativo di avviare un servizio all'avvio su Android


332

Ho cercato di avviare un servizio quando un dispositivo si avvia su Android, ma non riesco a farlo funzionare. Ho esaminato un numero di collegamenti online ma nessuno del codice funziona. Sto dimenticando qualcosa?

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

2
non so cosa ho fatto ma penso che funzioni ora potrebbe essere stato Android: permesso = "android.permission.RECEIVE_BOOT_COMPLETED" per il ricevitore
Alex

hai controllato il "_" extra in <action android: name = "android.intent.action._BOOT_COMPLETED" />
OneWorld

Esportato deve essere vero in modo che il sistema possa invocare il ricevitore, no? O è vero per impostazione predefinita?
Eugen Pechanec,

Risposte:


601

Le altre risposte sembrano buone, ma ho pensato di concludere tutto in una risposta completa.

È necessario quanto segue nel AndroidManifest.xmlfile:

  1. Nel tuo <manifest>elemento:

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
  2. Nel tuo <application>elemento (assicurati di usare un nome di classe [o relativo] completo per il tuo BroadcastReceiver):

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

    (non è necessario il android:enabled, exported, ecc, gli attributi: i valori di default di Android sono corretti)

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

Dalla domanda originale:

  • non è chiaro se l' <receiver>elemento fosse <application>nell'elemento
  • non è chiaro se è BroadcastReceiverstato specificato il nome di classe pienamente qualificato (o relativo) corretto per il
  • c'era un refuso nel <intent-filter>

2
Questo sembra buono. Lo userò come base, grazie :). Nessun segno di spunta o voti positivi o risposta purtroppo :(. Qualcuno lo verifica?
Nanne,

51
Solo un complemento: assicurati che la tua app sia installata nella memoria interna <manifest xmlns: android = "..." package = "..." android: installLocation = "internalOnly">
Bao Le

2
In Android Jellybean 4.2.2 nel tag <receiver> ho dovuto usare il nome relativo classe invece del nome completo per l'avvio del servizio, come rilevato nella stackoverflow.com/questions/16671619/...
Piovezan

6
Se il ricevitore viene utilizzato per cose diverse: <br> if ("android.intent.action.BOOT_COMPLETED" .equals (intent.getAction ())) {Intent serviceIntent = new Intent (context, Service_Location.class); // i.putExtra ("KEY1", "Valore utilizzato dal servizio"); context.startService (serviceIntent); }
Gunnar Bernstein,

2
In alternativa, dovresti estendere developer.android.com/reference/android/support/v4/content/… . È un aiuto per il modello comune di implementazione di un BroadcastReceiver che riceve un evento di riattivazione del dispositivo e quindi passa il lavoro a un servizio, garantendo nel contempo che il dispositivo non torni nuovamente in modalità di sospensione durante la transizione. Questa classe si occupa di creare e gestire un blocco parziale della sveglia per te; è necessario richiedere l'autorizzazione WAKE_LOCK per utilizzarlo.
Damian,

84

Come informazioni aggiuntive: BOOT_COMPLETE viene inviato alle applicazioni prima che venga montata la memoria esterna. Quindi se l'applicazione è installata su un archivio esterno non riceverà il messaggio di trasmissione BOOT_COMPLETE.

Maggiori dettagli qui nella sezione Ricevitori Broadcast in ascolto di "avvio completato"


Per evitare il problema precedente, lo sviluppatore potrebbe impostare "android: installLocation =" internalOnly "nel manifest per un'app. È una cattiva idea? Per un'app per smartphone, se il 99,9% (a mio avviso) di tutti gli utenti installa l'app normalmente , usando l'archiviazione interna anziché l'archiviazione esterna, sembra che l'aggiunta "internalOnly" al manifest andrebbe bene. Gradirei qualsiasi pensiero o idea tu abbia su questo.
AJW

69

Come avviare il servizio all'avvio del dispositivo (app di esecuzione automatica, ecc.)

Per prima cosa: dalla versione Android 3.1+ non ricevi BOOT_COMPLETE se l'utente non ha mai avviato l'app almeno una volta o l'applicazione "forza chiusa" dell'utente. Ciò è stato fatto per impedire al malware di registrare automaticamente il servizio. Questa falla di sicurezza è stata chiusa nelle versioni più recenti di Android.

Soluzione:

Crea un'app con attività. Quando l'utente lo esegue una volta, l'app può ricevere il messaggio di trasmissione BOOT_COMPLETE.

Per il secondo: BOOT_COMPLETE viene inviato prima che venga montata la memoria esterna. Se l'app è installata su un archivio esterno, non riceverà il messaggio di trasmissione BOOT_COMPLETE.

In questo caso esistono due soluzioni:

  1. Installa la tua app nella memoria interna
  2. Installa un'altra piccola app nella memoria interna. Questa app riceve BOOT_COMPLETE ed esegue la seconda app su memoria esterna.

Se l'app è già installata nella memoria interna, il codice seguente può aiutarti a capire come avviare il servizio all'avvio del dispositivo.


In Manifest.xml

Autorizzazione:

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

Registra il tuo ricevitore BOOT_COMPLETED:

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

Registra il tuo servizio:

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

Nel ricevitore 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);

    }

 }

Per HTC potresti dover aggiungere anche Manifest questo codice se il dispositivo non rileva RECEIVE_BOOT_COMPLETED:

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

Il ricevitore ora assomiglia a questo:

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

Come testare BOOT_COMPLETED senza riavviare l'emulatore o il dispositivo reale? È facile. Prova questo:

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

Come ottenere l'ID dispositivo? Ottieni un elenco di dispositivi collegati con ID:

adb devices

adb in ADT di default puoi trovare in:

adt-installation-dir/sdk/platform-tools

Godere! )


Il tuo primo paragrafo è stato il capitale. Non sono riuscito a farlo funzionare nel mio debugger.
estornes

34

Insieme a

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

anche usare,

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

I dispositivi HTC non sembrano catturare BOOT_COMPLETED


Devi aggiungere qualcosa di simile nelle autorizzazioni per i dispositivi HTC?
Nanda,

2
Questo potrebbe essere utile in alcune circostanze, ma capisco che HTC Fast Boot è una forma di ibernazione in cui lo stato del sistema viene salvato nel filesystem e android.intent.action.QUICKBOOT_POWERONviene inviato solo quando si ripristina da un avvio veloce. Ciò significa che non è necessario eseguire operazioni come la reimpostazione degli allarmi durante il ripristino da Avvio rapido man mano che vengono conservati. Pertanto sarebbe necessario utilizzarlo solo <action android:name="android.intent.action.QUICKBOOT_POWERON" />se si desidera fare qualcosa quando l'utente pensa che il dispositivo sia stato avviato.
HexAndBugs,

2
Dal punto di vista di uno sviluppatore di app, non dovremmo mai usarlo, se il comportamento esiste solo sui dispositivi HTC. Perché, BOOT_COMPLETED è, come da documentazione, verrà sempre inviato all'accensione del dispositivo. Qualche altro produttore potrebbe escogitare un altro metodo di avvio rapido e finiremmo per rovinare il nostro codice con le specifiche di ognuno.
Sottomissione Sebastian

@HexAndBugs Sei riuscito a confermare che Fast Boot è una forma di ibernazione in cui lo stato del sistema viene salvato nel filesystem? Voglio essere in grado di ripristinare gli allarmi che vengono utilizzati per future notifiche dopo un avvio rapido se lo stato del sistema non viene salvato ... si prega di avvisare.
AJW,

20

si noti che all'inizio della domanda, c'è un errore di battitura:

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

invece di :

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

un piccolo "_" e tutti questi problemi :)


13

Ho scoperto proprio ora che potrebbe essere a causa Fast Bootdell'opzione in Settings>Power

Quando questa opzione è disattivata, la mia applicazione riceve una trasmissione, ma non diversamente.

A proposito, ho Android 2.3.3su HTC Incredible S.

Spero che sia d'aiuto.


Causa sicuramente possibile del problema. Osservato anche su HTC Desire C con Android 4.0.3.
Zelimir


7

Dopo aver provato tutte le risposte e i trucchi citati, finalmente scopro perché il codice non funziona nel mio telefono. Alcuni telefoni Android come "Huawei Honor 3C Android 4.2.2 " hanno un menu Statup Manager nelle loro impostazioni e l'app deve essere selezionata nell'elenco. :)


5

Ho un ulteriore <category>tag, non so se questo fa la differenza.

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

Hai provato a inserire la clausola if "android.intent.action.BOOT_COMPLETED".equals(intent.getAction(), poiché il ricevitore probabilmente riceve comunque quell'intenzione?


ho provato questo e non ha funzionato ma ho dimenticato di dire che ho anche il <use-permesso android: name = "android.permission.RECEIVE_BOOT_COMPLETED" />
Alex

2
per ogni evenienza: l'aggiunta di android.intent.category.HOME a qualsiasi tag in AndroidManifest farà sì che Samsung Galaxy Tab esegua l'app in modalità compatibilità, anche dopo aver usato l'hack per disattivare la modalità compatibilità. non sono sicuro che sia lo stesso per le altre schede. consiglio di non impostare affatto la categoria HOME. non è necessario.
moonlightcheese


3

Prima di inviare la memoria esterna di montaggio BOOT_COMPLETE, se l'app viene installata su memoria esterna, non riceverà il messaggio di trasmissione BOOT_COMPLETE. Per evitare ciò, è possibile installare l'applicazione nella memoria interna. puoi farlo semplicemente aggiungendo questa riga in menifest.xml

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

Alcuni dispositivi HTC possono abilitare una funzione di "avvio veloce" che assomiglia di più a un letargo profondo e non a un vero riavvio e pertanto non dovrebbe fornire l'intento BOOT_COMPLETE. Per recuperarlo puoi aggiungere questo filtro di intenti nel tuo ricevitore:

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

Come suggerisci, per evitare il problema precedente, lo sviluppatore potrebbe impostare "android: installLocation =" internalOnly "nel manifest per un'app. È una cattiva idea? Per un'app per smartphone, se il 99,9% (la mia ipotesi) di tutti gli utenti installa l'app normalmente, usando l'archiviazione interna anziché l'archiviazione esterna, quindi sembra che l'aggiunta "internalOnly" al manifest andrebbe bene. Gradirei qualsiasi pensiero o idea tu abbia su questo. - AJW
AJW

3

Questo è quello che ho fatto

1. Ho creato 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. nel 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.e dopo TUTTO IL BISOGNO di "impostare" il ricevitore in MainActivity, potrebbe essere all'interno di 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);
...

l'ultima pila che ho imparato da ApiDemos


2

Se stai usando Android Studio e ami molto il completamento automatico, allora devo informarti, sto usando Android Studio v 1.1.0 e ho usato il completamento automatico per le seguenti autorizzazioni

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

E Android Studio ha completato automaticamente RECEIVE_BOOT_COMPLETEDtutto in minuscolo receive_boot_completede ho continuato a togliermi i capelli perché avevo già spuntato la mia lista di controllo per le cose da fare per avviare il servizio all'avvio. Ho appena confermato di nuovo

Android Studio completa automaticamente questa autorizzazione in minuscolo.


2

Come ha commentato @Damian, tutte le risposte in questa discussione stanno sbagliando. Farlo manualmente in questo modo comporta il rischio che il tuo Servizio venga interrotto a metà dallo spegnimento del dispositivo. È necessario prima ottenere un blocco sveglia. Fortunatamente, la libreria di supporto ci dà una classe per fare questo:

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

quindi, nel tuo Servizio, assicurati di rilasciare il blocco riattivazione:

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

Non dimenticare di aggiungere la procedura WAKE_LOCK al tuo mainfest:

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

Poca domanda ho un dubbio. Se il mio servizio è un servizio e non IntentService non posso utilizzare in questo modo, perché il metodo onHandleIntend non può essere ignorato in un servizio semplice ?
paolo2988,

Sto avendo lo stesso problema. Ti dispiace aiutarmi? Grazie! stackoverflow.com/questions/35373525/starting-my-service
Ruchir Baronia

Forse usare onNewIntent()? Oppure potresti cercare la fonte di IntentService e vedere cosa devi fare affinché il tuo Servizio sia
compatibile

1

In effetti, mi sono imbattuto in questo problema non molto tempo fa ed è davvero molto facile da risolvere, in realtà non fai nulla di sbagliato se imposti l' "android.intent.action.BOOT_COMPLETED"autorizzazione e il filtro intenti.

Tieni presente che se su Android 4.X devi eseguire il listener di trasmissione prima di avviare il servizio all'avvio, ciò significa che devi prima aggiungere un'attività, una volta che il tuo ricevitore di trasmissione è in esecuzione, l'app dovrebbe funzionare come previsto, tuttavia, su Android 4.X, non ho trovato un modo per avviare il servizio all'avvio senza alcuna attività, penso che Google lo abbia fatto per motivi di sicurezza.


0

Ho affrontato questo problema se lascio il costruttore vuoto nella classe del ricevitore. Dopo aver rimosso il contsructor vuoto, ricevere i methos ha iniziato a funzionare correttamente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.