web-dev-qa-db-fra.com

Comment redémarrer automatiquement un service même si l'utilisateur le ferme de force?

Je souhaite qu'un service s'exécute tout le temps dans mon application. Je souhaite donc le redémarrer même s’il est fermé de force par l’utilisateur. Il existe certainement un moyen de le faire en appliquant des applications comme Facebook (ce n'est pas fait avec la notification Push, Facebook redémarre son service même si Internet est désactivé).

Toute aide serait appréciée. Merci!

38
Vipul J

Tout d’abord, il est très mauvais modèle d’exécuter le service avec force contre la volonté de l’utilisateur.

Quoi qu'il en soit, vous pouvez le redémarrer en utilisant un BroadcastReceiver qui gère la diffusion envoyée à partir de onDestroy() de votre service.

StickyService.Java

public class StickyService extends Service
{
    private static final String TAG = "StickyService";


    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(TAG, "onStartCommand");
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        sendBroadcast(new Intent("YouWillNeverKillMe"));
    }

}

RestartServiceReceiver.Java

public class RestartServiceReceiver extends BroadcastReceiver
{

    private static final String TAG = "RestartServiceReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.e(TAG, "onReceive");
    context.startService(new Intent(context.getApplicationContext(), StickyService.class));

    }

}

Déclarez le fichier composants du manifeste:

    <service Android:name=".StickyService" >
    </service>

    <receiver Android:name=".RestartServiceReceiver" >
        <intent-filter>
            <action Android:name="YouWillNeverKillMe" >
            </action>
        </intent-filter>
    </receiver>

Démarrez le StickyService dans un composant (c'est-à-dire Application, Activity, Fragment):

startService(new Intent(this, StickyService.class));

OR

sendBroadcast(new Intent("YouWillNeverKillMe"));
65
Mehul Joisar

Vous devez créer un sticky service avec méthode onTaskRemoved prioritaire, dans laquelle vous pouvez configurer un service d’alarme pour déclencher à nouveau votre code.

public class BackgroundService extends Service {

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return START_STICKY;
    }

    @Override
    public void onTaskRemoved(Intent rootIntent) {
        //create an intent that you want to start again.
        Intent intent = new Intent(getApplicationContext(), BackgroundService.class);
        PendingIntent pendingIntent = PendingIntent.getService(this, 1, intent, PendingIntent.FLAG_ONE_SHOT);
        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        alarmManager.set(AlarmManager.RTC_WAKEUP, SystemClock.elapsedRealtime() + 5000, pendingIntent);
        super.onTaskRemoved(rootIntent);
    }
}

Également dans certains appareils comme Xiaomi, l'application Huwaei est fermée de force une fois qu'elle a été supprimée des applications récentes. En effet, les fabricants disposent de fonctionnalités de gestion des tâches qui améliorent les performances de la RAM/batterie.

Vous pouvez consulter ce lien pour plus d'informations: https://stackoverflow.com/a/41360159/2798289

11
Govind

Chaque fois qu'un service est tué, sa méthode onDestroy est toujours appelée. Il est préférable d'utiliser BroadcastReceiver pour démarrer votre service lorsqu'il est supprimé.

Voici un exemple de code illustrant sa mise en oeuvre: -

@Override
public void onDestroy() {
Intent in = new Intent();
in.setAction("StartkilledService");
sendBroadcast(in);
Log.d("debug", "Service Killed");
}

Puis enregistrez un destinataire dans AndroidManifest.xml: -

<receiver Android:name=".app.ServiceDestroyReceiver" >
    <intent-filter>
        <action Android:name="StartKilledService" >
        </action>
    </intent-filter>
</receiver>

Enfin, créez un BroadcastReceiver, et démarrez votre service avec la méthode onReceive: -

@Override
public void onReceive(Context context, Intent intent) {
Log.d("debug", "ServeiceDestroy onReceive...");
Log.d("debug", "action:" + intent.getAction());
Log.d("debug", "Starting Service");
ServiceManager.startService();
}

J'espère que cela t'aides.

4
Atish Agrawal

Selon le Android document

Starting from Android 3.1, the system's package manager keeps track of applications 
that are in a stopped state and provides a means of controlling their launch from 
background processes and other applications.

Note that an application's stopped state is not the same as an Activity's stopped
state. The system manages those two stopped states separately.
FLAG_INCLUDE_STOPPED_PACKAGES — Include intent filters of stopped applications in the
list of potential targets to resolve against.

FLAG_EXCLUDE_STOPPED_PACKAGES — Exclude intent filters of stopped applications from the
list of potential targets.

When neither or both of these flags is defined in an intent, the default behavior is to
include filters of stopped applications in the list of potential targets. 

Note that the system adds FLAG_EXCLUDE_STOPPED_PACKAGES to all broadcast intents.
It does this to prevent broadcasts from background services from inadvertently or
unnecessarily launching components of stopped applications. A background service 
or application can override this behavior by adding the FLAG_INCLUDE_STOPPED_PACKAGES
flag to broadcast intents that should be allowed to activate stopped applications.

À l'arrêt forcé de l'application, Android supprimez simplement l'ID de processus. Aucun avertissement, des rappels sont donnés au service/aux activités. Selon le Android document, lorsque le L'application est tuée, il y a des chances qu'elle appelle onPause ().

Quand j'ai essayé dans mon application, même onPause () n'a pas été appelé. Je pense que le seul moyen est d'utiliser l'indicateur d'intention FLAG_INCLUDE_STOPPED_PACKAGES Et de l'envoyer depuis une autre application.

4
Zohra Khan

sur la méthode startCommand du service, retournez START_STICKY. généralement, il demande au système d'exploitation de démarrer le service quand il est tué.

3
Bijesh

Si je comprends bien, cela n’est pas possible Android pour forcer la fermeture de l’application a été conçue pour permettre à l’utilisateur de se débarrasser des applications non souhaitées, de sorte qu’il n’autorise aucune activité jusqu’à ce que l’utilisateur redémarre l'une de ses activités.

Redémarrez le service même si l'application est à l'arrêt forcé et maintenez le service en arrière-plan même après la fermeture de l'application Comment?

2
marcinj

Si la situation permet d'utiliser 'root', il est généralement possible d'appliquer le paradigme Humpty-Dumpty.

Votre application (1ère) installe une autre application (2e, prenant APK des actifs) et exécute le service de la 2e application. Le service de la 2e application se lie au premier service de l'application et se rétablit lorsqu'il est déconnecté. La 1ère application fait la même chose.

Bien sûr, cela ne va pas aider lorsque toutes les applications sont tuées par une application gratuite RAM ou similaire, mais lorsque Android tue l’une de ces deux applications, l’autre redémarre sa homologue.

2
OGP

La seule solution réelle pour maintenir les services en vie consiste à appeler Service.startForeground(...) avec une notification fournie. Ce sera la seule solution valable. Les deux autres dépendront beaucoup de la manière dont Google modifiera le comportement de son système. Avec chaque mise à jour de l'API, Google pourrait empêcher tout piratage sur deux.

Cela permet également à l'utilisateur de savoir que votre application exécute une tâche en arrière-plan qui la maintiendra en vie et que l'utilisateur doit l'arrêter. Si vous donnez à l'utilisateur la possibilité de l'arrêter, cela fait partie de votre application.

Voir la documentation:

void startForeground (int id, Notification notification)

Faites en sorte que ce service soit exécuté au premier plan, en fournissant la notification en cours à afficher à l'utilisateur lorsqu'il se trouve dans cet état. Par défaut, les services sont en arrière-plan, ce qui signifie que si le système doit les supprimer pour récupérer davantage de mémoire (par exemple, pour afficher une page volumineuse dans un navigateur Web), ils peuvent être supprimés sans trop de dégâts. Vous pouvez définir cet indicateur si la suppression de votre service perturberait l'utilisateur, par exemple si votre service effectuait la lecture de musique de fond, afin que l'utilisateur puisse remarquer si la lecture de leur musique était arrêtée.

1
da_berni

Il existe une solution très astucieuse pour maintenir le service en marche même si vous forcez l’arrêter. Je ne le recommande pas, car cela va à l'encontre de la volonté de l'utilisateur. Vous pouvez définir un récepteur de diffusion pour qu'il reçoive une intention avec l'action X. Gestionnaire onStartCommand de votre service, diffusion X (si le service n'est pas encore démarré). sur le récepteur de diffusion à la réception de X, démarrez d’abord le service, puis attendez quelques minutes, puis rediffusez X.

0
Nami