Intentando iniciar un servicio de arranque en Android

332

He estado intentando iniciar un servicio cuando un dispositivo se inicia en Android, pero no puedo hacer que funcione. He visto varios enlaces en línea, pero ninguno de los códigos funciona. ¿Estoy olvidando algo?

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

Receptor de radiodifusión

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
fuente
2
No sé lo que hice, pero creo que funciona ahora, podría haber sido el android: permission = "android.permission.RECEIVE_BOOT_COMPLETED" para el receptor
Alex
¿has marcado el "_" extra en <action android: name = "android.intent.action._BOOT_COMPLETED" />
OneWorld
La exportación debe ser verdadera para que el sistema pueda invocar al receptor, ¿no? ¿O es cierto por defecto?
Eugen Pechanec
para Oreo, mira aquí: stackoverflow.com/questions/44502229/…
Andy Weinstein

Respuestas:

601

Las otras respuestas se ven bien, pero pensé que resumiría todo en una respuesta completa.

Necesita lo siguiente en su AndroidManifest.xmlarchivo:

  1. En tu <manifest>elemento:

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
  2. En su <application>elemento (asegúrese de utilizar un nombre de clase totalmente calificado [o relativo] para su BroadcastReceiver):

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

    (no es necesario el android:enabled, exported, etc., atributos: los valores por defecto de Android son correctos)

    En 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 pregunta original:

  • no está claro si el <receiver>elemento estaba en el <application>elemento
  • no está claro si BroadcastReceiverse especificó el nombre de clase correcto completo (o relativo) para
  • hubo un error tipográfico en el <intent-filter>
Timo Bruck
fuente
2
Esto luce bien. Voy a usar esto como base, gracias :). . Sin marca de verificación o upvotes o respuesta por desgracia :( Cualquier verificar esto?
Nanne
51
Solo un complemento: asegúrese de que su aplicación esté instalada en la memoria interna <manifest xmlns: android = "..." package = "..." android: installLocation = "internalOnly">
Bao Le
2
En Android Jellybean 4.2.2 en la etiqueta <receiver> tuve que usar el nombre relativo de la clase en lugar del nombre completo para que se inicie el servicio, como se indica en stackoverflow.com/questions/16671619/…
Piovezan
66
Si el receptor se usa para diferentes cosas: <br> if ("android.intent.action.BOOT_COMPLETED" .equals (intent.getAction ())) {Intent serviceIntent = new Intent (context, Service_Location.class); // i.putExtra ("KEY1", "Valor que utilizará el servicio"); context.startService (serviceIntent); }
Gunnar Bernstein
2
En su lugar, debe extender developer.android.com/reference/android/support/v4/content/… . Es un Ayudante para el patrón común de implementar un BroadcastReceiver que recibe un evento de activación del dispositivo y luego pasa el trabajo a un Servicio, mientras se asegura de que el dispositivo no vuelva a dormir durante la transición. Esta clase se encarga de crear y administrar un bloqueo de activación parcial para usted; debes solicitar el permiso WAKE_LOCK para usarlo.
Damian
84

Como información adicional: BOOT_COMPLETE se envía a las aplicaciones antes de montar el almacenamiento externo. Entonces, si la aplicación está instalada en el almacenamiento externo, no recibirá el mensaje de difusión BOOT_COMPLETE.

Más detalles aquí en la sección Receptores de difusión que escuchan "arranque completado"

inazaruk
fuente
Para evitar el problema anterior, el desarrollador podría establecer "android: installLocation =" internalOnly "en el manifiesto de una aplicación. ¿Es una mala idea? Para una aplicación de teléfono inteligente, si el 99.9% (supongo) de todos los usuarios instala la aplicación normalmente , al usar almacenamiento interno en lugar de almacenamiento externo, parece que la adición "internamente" al manifiesto estaría bien. Agradecería cualquier pensamiento o idea que tenga sobre esto.
AJW
69

Cómo iniciar el servicio en el arranque del dispositivo (aplicación de ejecución automática, etc.)

Primero: desde la versión Android 3.1+ no recibe BOOT_COMPLETE si el usuario nunca inició su aplicación al menos una vez o si el usuario "forzó el cierre" de la aplicación. Esto se hizo para evitar que el malware registre automáticamente el servicio. Este agujero de seguridad se cerró en las versiones más recientes de Android.

Solución:

Crear aplicación con actividad. Cuando el usuario lo ejecuta una vez, la aplicación puede recibir un mensaje de difusión BOOT_COMPLETE.

Para el segundo: BOOT_COMPLETE se envía antes de que se monte el almacenamiento externo. Si la aplicación está instalada en el almacenamiento externo, no recibirá el mensaje de difusión BOOT_COMPLETE.

En este caso hay dos soluciones:

  1. Instala tu aplicación en el almacenamiento interno
  2. Instale otra aplicación pequeña en el almacenamiento interno. Esta aplicación recibe BOOT_COMPLETE y ejecuta la segunda aplicación en almacenamiento externo.

Si su aplicación ya está instalada en el almacenamiento interno, el siguiente código puede ayudarlo a comprender cómo iniciar el servicio en el arranque del dispositivo.


En Manifiesto.xml

Permiso:

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

Registre su receptor BOOT_COMPLETED:

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

Registre su servicio:

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

En el receptor 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);

    }

 }

Para HTC, es posible que también necesite agregar Manifest este código si el dispositivo no atrapa RECEIVE_BOOT_COMPLETED:

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

El receptor ahora se ve así:

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

¿Cómo probar BOOT_COMPLETED sin emulador de reinicio o dispositivo real? Es fácil. Prueba esto:

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

¿Cómo obtener la identificación del dispositivo? Obtenga una lista de dispositivos conectados con identificaciones:

adb devices

adb en ADT por defecto lo puedes encontrar en:

adt-installation-dir/sdk/platform-tools

¡Disfrutar! )

usuario3439968
fuente
Tu primer párrafo fue capital. No pude ejecutarlo en mi depurador.
estornes
34

Junto con

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

también use,

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

Los dispositivos HTC no parecen atrapar BOOT_COMPLETED

Tony
fuente
¿Necesita agregar algo similar en permisos para dispositivos HTC?
Nanda
2
Esto podría ser útil en algunas circunstancias, pero entiendo que el arranque rápido de HTC es una forma de hibernación donde el estado del sistema se guarda en el sistema de archivos, y android.intent.action.QUICKBOOT_POWERONsolo se envía al restaurar desde el arranque rápido. Esto significa que no es necesario hacer cosas como restablecer las alarmas cuando se recupera de Fast Boot, ya que se conservan. Por lo tanto, solo sería necesario usarlo <action android:name="android.intent.action.QUICKBOOT_POWERON" />si desea hacer algo cuando el usuario cree que el dispositivo se ha iniciado.
HexAndBugs
2
Desde la perspectiva de un desarrollador de aplicaciones, nunca deberíamos usar esto, si el comportamiento existe solo en dispositivos HTC. Porque, BOOT_COMPLETED, según la documentación, siempre se enviará cuando el dispositivo se ENCIENDA. Algún otro fabricante podría idear otro método de arranque rápido y terminaríamos alterando nuestro código con las especificaciones de cada uno.
Subin Sebastian
@HexAndBugs ¿Pudiste confirmar que Fast Boot es una forma de hibernación donde el estado del sistema se guarda en el sistema de archivos? Quiero poder restablecer las alarmas que se utilizan para notificaciones futuras después de un inicio rápido si el estado del sistema no se guarda ... por favor avise.
AJW
20

Tenga en cuenta que al comienzo de la pregunta, hay un error tipográfico:

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

en vez de :

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

un pequeño "_" y todos estos problemas :)

Evgeny Erlihman
fuente
13

Descubrí hace un momento que podría deberse a la Fast Bootopción en Settings>Power

Cuando tengo esta opción desactivada, mi aplicación recibe esta transmisión pero no de otra manera.

Por cierto, tengo Android 2.3.3en HTC Incredible S.

Espero eso ayude.

Omer Akhter
fuente
Definitivamente posible causa del problema. Observado también en HTC Desire C con Android 4.0.3.
Zelimir
7

Después de probar todas las respuestas y trucos mencionados, finalmente encuentro por qué el código no funciona en mi teléfono. Algunos teléfonos Android como "Huawei Honor 3C Android 4.2.2 " tienen un menú de Statup Manager en su configuración y su aplicación debe estar marcada en la lista. :)

Amir
fuente
5

Tengo una <category>etiqueta adicional , no sé si eso hace alguna diferencia.

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

¿Has intentado omitir la cláusula if "android.intent.action.BOOT_COMPLETED".equals(intent.getAction(), ya que el receptor probablemente solo recibe esa intención de todos modos?

Mella
fuente
probé esto y no funcionó por cierto, olvidé mencionar que también tengo el <uses-permission android: name = "android.permission.RECEIVE_BOOT_COMPLETED" />
Alex
2
por si acaso: agregar android.intent.category.HOME a cualquier etiqueta en el AndroidManifest hará que el Samsung Galaxy Tab ejecute la aplicación en modo de compatibilidad, incluso después de usar el truco para desactivar el modo de compatibilidad. No estoy seguro si esto es lo mismo para otras pestañas. Recomiendo no establecer la categoría HOME en absoluto. Es innecesario.
moonlightcheese
3

Antes de montar el almacenamiento externo, BOOT_COMPLETE se envía a ejecutar. Si su aplicación está instalada en el almacenamiento externo, no recibirá el mensaje de difusión BOOT_COMPLETE. Para evitar esto, puede instalar su aplicación en el almacenamiento interno. puede hacer esto simplemente agregando esta línea en menifest.xml

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

Algunos dispositivos HTC pueden habilitar una función de "arranque rápido" que se parece más a una hibernación profunda y no a un reinicio real y, por lo tanto, no debe dar la intención BOOT_COMPLETE. Para recuperar esto, puede agregar este filtro de intención dentro de su receptor:

            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.QUICKBOOT_POWERON" />
            </intent-filter>
MD Sajedul Karim
fuente
Como sugiere, para evitar el problema anterior, el desarrollador podría establecer "android: installLocation =" internalOnly "en el manifiesto de una aplicación. ¿Es una mala idea? Para una aplicación de teléfono inteligente, si el 99.9% (supongo) de todos los usuarios instale la aplicación normalmente, utilizando almacenamiento interno en lugar de almacenamiento externo, entonces parece que la adición "internamente" al manifiesto estaría bien. Agradecería cualquier idea o idea que tenga sobre esto. - AJW
AJW
3

Esto es lo que hice

1. Hice la clase de receptor

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.en el manifiesto

<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. y después de TODO LO QUE NECESITA "configurar" el receptor en su MainActivity, puede estar dentro de 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);
...

el último paso que aprendí de ApiDemos

San Juan
fuente
2

Si está utilizando Android Studio y le gusta mucho el autocompletado, debo informarle que estoy usando Android Studio v 1.1.0 y usé el autocompletado para el siguiente permiso

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

Y Android Studio Auto completó RECEIVE_BOOT_COMPLETEDtodo en minúsculas receive_boot_completedy seguí arrancándome el pelo porque ya había marcado mi lista de verificación para saber qué hacer para comenzar el servicio en el arranque. Acabo de confirmar de nuevo

Android Studio REALIZA automáticamente este permiso en minúsculas.

Haroon Dilshad
fuente
2

Como comentó @Damian, todas las respuestas en este hilo lo están haciendo mal. Hacerlo manualmente de esta manera corre el riesgo de que su Servicio se detenga en el medio del dispositivo que se va a dormir. Primero debe obtener un bloqueo de activación. Afortunadamente, la biblioteca de soporte nos da una clase para hacer esto:

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

luego, en su Servicio, asegúrese de liberar el bloqueo de activación:

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

No olvides agregar la permiso WAKE_LOCK a tu fiesta principal:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
phreakhead
fuente
Pequeña pregunta que tengo una duda. Si mi servicio es un Servicio y no IntentService , no puedo usarlo de esta manera, porque el método onHandleIntend no se puede anular en un Servicio simple .
paolo2988
Estoy teniendo el mismo problema. ¿Te importaría ayudarme? ¡Gracias! stackoverflow.com/questions/35373525/starting-my-service
Ruchir Baronia
Tal vez usar onNewIntent()? O bien, puede consultar la fuente de IntentService y ver qué necesita hacer para que su Servicio coincida ...
phreakhead
1

De hecho, me metí en este problema no hace mucho, y es realmente muy fácil de solucionar, en realidad no haces nada malo si configuras el "android.intent.action.BOOT_COMPLETED"permiso y el filtro de intención.

Tenga en cuenta que si en Android 4.X, debe ejecutar el escucha de transmisión antes de comenzar el servicio en el arranque, eso significa que primero debe agregar una actividad, una vez que su receptor de transmisión se esté ejecutando, su aplicación debería funcionar como esperaba, Sin embargo, en Android 4.X, no he encontrado una manera de iniciar el servicio en el arranque sin ninguna actividad, creo que Google lo hizo por razones de seguridad.

David Hx
fuente
0

Me enfrenté a este problema si dejo el constructor vacío en la clase de receptor. Después de quitar el contsructor vacío en Metodos de recepción comenzó a funcionar bien.

redrom
fuente