Android: servicio de inicio en el momento del arranque

109

Necesito iniciar un servicio en el momento del arranque. Busqué mucho. Están hablando de Broadcastreceiver. Como soy nuevo en el desarrollo de Android, no obtuve una imagen clara sobre los servicios en Android. Proporcione algún código fuente.

harish
fuente
25
@ user244540: Por favor, no "inicie un servicio en el momento del arranque" con la intención de que se ejecute para siempre, a menos que esté entregando valor continuamente (por ejemplo, un cliente VOIP). En esos casos, utilícelo startForeground()en su servicio. De lo contrario, Android y sus usuarios eliminarán su servicio por ser una pérdida de espacio y obtendrá algunos comentarios desagradables en Android Market. En la mayoría de las situaciones en las que cree que desea que un servicio se inicie en el momento del arranque, es mejor utilizarlo AlarmManagerpara que su servicio pueda ejecutarse periódicamente en lugar de de forma continua .
CommonsWare
2
@CommonsWare: Buen punto. Sin embargo, tenga en cuenta que para iniciar ejecuciones periódicas AlarmManagerdespués del reinicio, debe seguir pasos muy similares (la diferencia está en el contenido del onReceivemétodo)
stanwise
1
@CommonsWare: Muy buen comentario, me encontré con esta pregunta y tu sugerencia se ajusta exactamente a mi situación. Si fuera una respuesta, la habría votado a favor :-)
chiccodoro

Respuestas:

95

Cree un BroadcastReceivery regístrelo para recibir ACTION_BOOT_COMPLETED . También necesita el permiso RECEIVE_BOOT_COMPLETED .

Leer: Escuchar y transmitir mensajes globales y configurar alarmas

Peter Knego
fuente
2
¿Qué pasa con el bloqueo de activación? mientras se inicia el servicio, el dispositivo puede decidir quedarse dormido ...
Marian Paździoch
¿Necesito arrancar mi móvil al menos una vez para iniciar un servicio?
pathe.kiran
@ MarianPaździoch tiene razón; necesitas un bloqueo de activación. Vea mi respuesta a continuación: stackoverflow.com/a/30970167/473201
phreakhead
@ pathe.kiran en el arranque, sí. Consulte commonsware.com/blog/2011/07/05/boot-completed-regression.html
Tim
Su última URL está desactualizada
Prizoff
192

Su receptor:

public class MyReceiver extends BroadcastReceiver {   

    @Override
    public void onReceive(Context context, Intent intent) {

     Intent myIntent = new Intent(context, YourService.class);
     context.startService(myIntent);

    }
}

Su AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.broadcast.receiver.example"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true">

        <activity android:name=".BR_Example"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    <!-- Declaring broadcast receiver for BOOT_COMPLETED event. -->
        <receiver android:name=".MyReceiver" android:enabled="true" android:exported="false">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>

    </application>

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

</manifest>
Vladimir Ivanov
fuente
5
El enlace al artículo está muerto, pero el código de muestra es todo lo que necesita de todos modos, así que +1 :)
Alex
3
En realidad, necesita pocas mejoras, debe usar wakelock en el receptor, de lo contrario hay una pequeña posibilidad de que su servicio no se inicie.
Vladimir Ivanov
¿Necesito arrancar mi móvil al menos una vez para que esto funcione?
pathe.kiran
1
No, pero debes ejecutar la aplicación al menos una desde Android 3.0
Vladimir Ivanov
¿Funciona esto si se fuerza el cierre de la aplicación desde la configuración? ¿Seguirá despertando la aplicación?
Srihari Karanth
32

Es posible registrar su propio servicio de aplicaciones para que se inicie automáticamente cuando se haya iniciado el dispositivo. Necesita esto, por ejemplo, cuando desea recibir eventos push de un servidor http y desea informar al usuario tan pronto como ocurra un nuevo evento. El usuario no tiene que iniciar la actividad manualmente antes de que se inicie el servicio ...

Es muy sencillo. Primero dé a su aplicación el permiso RECEIVE_BOOT_COMPLETED. A continuación, debe registrar un BroadcastReveiver. Lo llamamos BootCompletedIntentReceiver.

Su Manifest.xml ahora debería verse así:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="com.jjoe64">
 <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
 <application>
  <receiver android:name=".BootCompletedIntentReceiver">
   <intent-filter>
    <action android:name="android.intent.action.BOOT_COMPLETED" />
   </intent-filter>
  </receiver>
  <service android:name=".BackgroundService"/>
 </application>
</manifest>

Como último paso, debe implementar el receptor. Este receptor acaba de iniciar su servicio en segundo plano.

package com.jjoe64;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;

import com.jjoe64.BackgroundService;

public class BootCompletedIntentReceiver extends BroadcastReceiver {
 @Override
 public void onReceive(Context context, Intent intent) {
  if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
   Intent pushIntent = new Intent(context, BackgroundService.class);
   context.startService(pushIntent);
  }
 }
}

De http://www.jjoe64.com/2011/06/autostart-service-on-device-boot.html

appsthatmatter
fuente
3
Igual que el anterior pero realmente simple y rápido, usa este si vienes por esta publicación.
dbkoren
La única diferencia es que esto declara el Servicio en el Manifiesto, lo cual es correcto.
Joaquin Iurchuk
No solo es correcto declarar su servicio en el manifiesto, es obligatorio. Igual que con las actividades
Tim
¿Dónde está la actividad principal? ¡No es correcto hacer una aplicación sin actividades o android.intent.category.LAUNCHER!
nick
@ L'Esperanza seguro, ¡puedes tener aplicaciones que no tienen actividades visibles!
appsthatmatter
15

A la mayoría de las soluciones publicadas aquí les falta una pieza importante: hacerlo sin un bloqueo de activación corre el riesgo de que su Servicio se elimine antes de que termine de procesarse. Vi esta solución en otro hilo, respondiendo aquí también.

Dado que WakefulBroadcastReceiver está obsoleto en api 26, se recomienda para niveles de API inferiores a 26

Necesita 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 olvide agregar el permiso WAKE_LOCK y registrar su receptor en el manifiesto:

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

...

<service android:name=".SimpleWakefulReceiver">
    <intent-filter>
        <action android:name="com.example.SimpleWakefulReceiver"/>
    </intent-filter>
</service>
phreakhead
fuente
1
En el archivo de manifiesto, SimpleWakefulReceiver no es un servicio.
Desmond Lua
1
WakefulBroadcastReceiver está obsoleto
Amin Pinjari
5

debe registrarse para BOOT_COMPLETE y REBOOT

<receiver android:name=".Services.BootComplete">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED"/>
            <action android:name="android.intent.action.REBOOT"/>
        </intent-filter>
    </receiver> 
Raafat Alhmidi
fuente
2
La literatura dice que 'android.intent.action.REBOOT' solo puede ser utilizado por una aplicación / código privilegiado. ¿Qué ventaja tiene esto de otra manera?
XMAN
1

También registre su servicio creado en el Manifiesto y use-permiso como

<application ...>
   <service android:name=".MyBroadcastReceiver">
        <intent-filter>
            <action android:name="com.example.MyBroadcastReciver"/>
        </intent-filter>
   </service>
</application>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

y luego en braod cast Reciever llama a tu servicio

public class MyBroadcastReceiver extends BroadcastReceiver 
{
    @Override
    public void onReceive(Context context, Intent intent)
    {
        Intent myIntent = new Intent(context, MyService.class);
        context.startService(myIntent);
    }
}
SoftEye
fuente
¿Por qué el filtro de intención dentro del servicio?
Joaquin Iurchuk
porque cuando se complete el arranque, se llamará a
MyService
En ese caso, su clase de servicio ampliará el servicio y el receptor de transmisión. Estoy en lo cierto?
Joaquin Iurchuk
La clase ampliará la clase de servicio.
SoftEye
2
Algo anda mal aquí. Se supone que el servicio se llama desde el receptor de transmisión. Pero está diciendo que su servicio es el receptor de transmisión y luego me dice que la clase de servicio no extiende el receptor de transmisión. Por lo tanto, no recibirá la transmisión de inicio completo. ¿Qué está anulando cuando declara el método onReceive?
Joaquin Iurchuk
0

Primero registre un receptor en su archivo manifest.xml:

    <receiver android:name="com.mileagelog.service.Broadcast_PowerUp" >
        <intent-filter>
            <action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
            <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
        </intent-filter>
    </receiver>

y luego escribe una transmisión para este receptor como:

public class Broadcast_PowerUp extends BroadcastReceiver {

  @Override
  public void onReceive(Context context, Intent intent) {
    String action = intent.getAction();

    if (action.equals(Intent.ACTION_POWER_CONNECTED)) {
        Toast.makeText(context, "Service_PowerUp Started",
                Toast.LENGTH_LONG).show();


    } else if (action.equals(Intent.ACTION_POWER_DISCONNECTED)) {



        Toast.makeText(context, "Service_PowerUp Stoped", Toast.LENGTH_LONG)
        .show();
    }
  }
}
Manoj Tarkar
fuente
0

Para reiniciar el servicio en Android Oo más, es decir, SO> 28 Use este código VERSIÓN KOTLIN 1) Agregue permiso en el manifiesto

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

2) Cree un Classy extiéndalo conBroadcastReceiver

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.Build
import android.util.Log
import androidx.core.content.ContextCompat



class BootCompletedReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, arg1: Intent?) {
        Log.d("BootCompletedReceiver", "starting service...")
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            ContextCompat.startForegroundService(context, Intent(context, YourServiceClass::class.java))
        } else {
            context.startService(Intent(context, YourServiceClass::class.java))
        }
    }
}

3) Declare en un archivo de manifiesto como este en la etiqueta de la aplicación

<receiver android:name=".utils.BootCompletedReceiver" >
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
            <action android:name="android.intent.action.QUICKBOOT_POWERON" />
        </intent-filter>
    </receiver>
Aprende rápido
fuente
-1

Por favor, consulte JobScheduler para saber si hay apis superiores a 26

WakeLock fue la mejor opción para esto, pero está en desuso en el nivel de API 26. Por favor, consulte este enlace si considera niveles de API superiores a 26
https://developer.android.com/reference/android/support/v4/content/WakefulBroadcastReceiver.html# startWakefulService (android.content.Context,% 20android.content.Intent)

Dice

A partir de Android O, las restricciones de verificación de antecedentes hacen que esta clase ya no sea útil en general. (Por lo general, no es seguro iniciar un servicio desde la recepción de una transmisión, porque no tiene ninguna garantía de que su aplicación esté en primer plano en este punto y, por lo tanto, se le permita hacerlo). En su lugar, los desarrolladores deben usar Android. app.job.JobScheduler para programar un trabajo, y esto no requiere que la aplicación mantenga un bloqueo de activación mientras lo hace (el sistema se encargará de mantener un bloqueo de activación para el trabajo).

así que como dice cosider JobScheduler
https://developer.android.com/reference/android/app/job/JobScheduler

si es para hacer algo que para empezar y quedárselo puedes recibir la retransmisión ACTION_BOOT_COMPLETED

Si no se trata de primer plano, compruebe si un servicio de accesibilidad podría funcionar

otra opción es iniciar una actividad desde el receptor de transmisión y finalizarla después de iniciar el servicio dentro de onCreate (), ya que las versiones más nuevas de Android no permiten iniciar servicios desde receptores

Duro
fuente