Comment démarrerForeground () sans afficher de notification?

Je veux créer un service et le faire fonctionner au premier plan.

La plupart des codes d’exemple contiennent des notifications. Mais je ne veux pas afficher de notification. Est-ce possible?

Pouvez-vous me donner des exemples? Y a-t-il des alternatives?

Mon service d’application fait du mediaplayer. Comment faire en sorte que le système ne tue pas mon service, sauf que l’application le tue lui-même (par exemple, en interrompant ou en arrêtant la musique par bouton).

En tant que fonctionnalité de sécurité de la plate-forme Android, vous ne pouvez en aucun cas disposer d’un service de premier plan sans notification. En effet, un service mis en avant consum plus de ressources et est soumis à des contraintes d’ordonnancement (c’est-à-dire qu’il ne se tue pas aussi vite) que les services en arrière-plan. Alors, ne fais pas ça.

Cependant, il est possible d’avoir une “fausse” notification, c’est-à-dire que vous pouvez créer une icône de notification transparente (iirc). Ceci est extrêmement déloyal pour vos utilisateurs, et vous n’avez aucune raison de le faire, sauf pour tuer leur batterie et créer ainsi des logiciels malveillants.

Mise à jour: Ceci a été “corrigé” sur Android 7.1. https://code.google.com/p/android/issues/detail?id=213309

Depuis la mise à jour 4.3, il est fondamentalement impossible de démarrer un service avec startForeground() sans afficher de notification.

Vous pouvez cependant masquer l’icône en utilisant les API officielles … pas besoin d’icône transparente: (Utilisez NotificationCompat pour prendre en charge les anciennes versions)

 NotificationCompat.Builder builder = new NotificationCompat.Builder(context); builder.setPriority(Notification.PRIORITY_MIN); 

J’ai fait la paix avec le fait que la notification elle-même doit toujours être là, mais pour qui qui veut toujours le cacher, j’ai peut-être trouvé une solution pour cela:

  1. Démarrez un faux service avec startForeground() avec la notification et tout.
  2. Démarrez le service réel que vous souhaitez exécuter, également avec startForeground() (même ID de notification)
  3. Arrêtez le premier service (faux) (vous pouvez appeler stopSelf() et dans l’appel stopForeground(true) ).

Voilà! Aucune notification et votre deuxième service continue à fonctionner.

Voici ma mise en œuvre de la technique dans la réponse de Lior Iluz .

Notez que cela ne fonctionne plus dans Android 7.1. Notez également que cette technique pourrait être interprétée comme une violation des règles de développement de Google Play ( Apps that introduce or exploit security vulnerabilities. ).

Code

Avant-planService.java

 public class ForegroundService extends Service { static ForegroundService instance; @Override public void onCreate() { super.onCreate(); instance = this; if (startService(new Intent(this, ForegroundEnablingService.class)) == null) throw new RuntimeException("Couldn't find " + ForegroundEnablingService.class.getSimpleName()); } @Override public void onDestroy() { super.onDestroy(); instance = null; } @Override public IBinder onBind(Intent intent) { return null; } } 

Au premier planEnablingService.java

 public class ForegroundEnablingService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { if (ForegroundService.instance == null) throw new RuntimeException(ForegroundService.class.getSimpleName() + " not running"); //Set both services to foreground using the same notification id, resulting in just one notification startForeground(ForegroundService.instance); startForeground(this); //Cancel this service's notification, resulting in zero notifications stopForeground(true); //Stop this service so we don't waste RAM. //Must only be called *after* doing the work or the notification won't be hidden. stopSelf(); return START_NOT_STICKY; } private static final int NOTIFICATION_ID = 10; private static void startForeground(Service service) { Notification notification = new Notification.Builder(service).getNotification(); service.startForeground(NOTIFICATION_ID, notification); } @Override public IBinder onBind(Intent intent) { return null; } } 

AndroidManifest.xml

   

Compatibilité

Testé et travaillant sur:

  • Émulateur officiel
    • 4.0.2
    • 4.1.2
    • 4.2.2
    • 4.3.1
    • 4.4.2
    • 5.0.2
    • 5.1.1
    • 6,0
    • 7.0
  • Sony Xperia M
    • 4.1.2
    • 4.3
  • Samsung Galaxy ?
    • 4.4.2
    • 5.X
  • Genymotion
    • 5.0
    • 6,0
  • CyanogèneMod
    • 5.1.1

Ne fonctionne plus à partir d’Android 7.1.

Vous pouvez utiliser ceci:

  Notification note = new Notification( 0, null, System.currentTimeMillis() ); note.flags |= Notification.FLAG_NO_CLEAR; startForeground( 42, note ); 

comme suggéré par @Kristopher Micinski

—–METTRE À JOUR

S’il vous plaît noter que ce n’est plus autorisé avec les versions Android KitKat +. Et gardez à l’esprit que cela viole plus ou moins le principe de conception d’Android qui rend les opérations d’arrière-plan visibles pour les utilisateurs, comme mentionné par @Kristopher Micinski

Il suffit de définir l’ID de votre notification à zéro:

 // field for notification ID private static final int NOTIF_ID = 0; ... startForeground(NOTIF_ID, mBuilder.build()); NotificationManager mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); mNotificationManager.cancel(NOTIF_ID); ... 

Un avantage que vous pouvez obtenir est qu’un Service sera capable de fonctionner en haute priorité sans être détruit par le système Android, sauf si la pression de la mémoire est élevée.

MODIFIER

Pour le faire fonctionner avec Pre-Honeycomb et Android 4.4 et versions ultérieures, veillez à utiliser NotificationCompat.Builder fourni par Support Library v7, au lieu de Notification.Builder .

Je mets à zéro le paramètre d’icône du constructeur pour Notification, puis transmets la notification résultante à startForeground (). Aucune erreur dans le journal et aucune notification ne s’affiche. Je ne sais pas si le service a été mis au premier plan – existe-t-il un moyen de vérifier?

Édité: Vérifié avec dumpsys, et en effet le service est mis en avant sur mon système 2.3. Je n’ai pas encore vérifié avec d’autres versions de système d’exploitation.

Il y a une solution de contournement. Essayez de créer une notification sans définir d’icône, et la notification ne s’affiche pas. Je ne sais pas comment ça marche, mais ça marche 🙂

  Notification notification = new NotificationCompat.Builder(this) .setContentTitle("Title") .setTicker("Title") .setContentText("App running") //.setSmallIcon(R.drawable.picture) .build(); startForeground(101, notification); 

la version 4.3 (18) et les notifications de masquage ci-dessus ne sont pas possibles, mais vous pouvez désactiver l’icône, version 4.3 (18) et ci-dessous, il est possible de masquer la notification

 Notification noti = new Notification(); if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) { noti.priority = Notification.PRIORITY_MIN; } startForeground(R.ssortingng.app_name, noti); 

J’ai trouvé sur Android 8.0 qu’il est toujours possible de ne pas utiliser de canal de notification.

 public class BootCompletedIntentReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { Intent notificationIntent = new Intent(context, BluetoothService.class); context.startForegroundService(notificationIntent); } else { //... } } } } 

Et dans BluetoothService.class:

  @Override public void onCreate(){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { Intent notificationIntent = new Intent(this, BluetoothService.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); Notification notification = new Notification.Builder(this) .setContentTitle("Title") .setContentText("App is running") .setSmallIcon(R.drawable.notif) .setContentIntent(pendingIntent) .setTicker("Title") .setPriority(Notification.PRIORITY_DEFAULT) .build(); startForeground(15, notification); } } 

Une notification persistante ne s’affiche pas, mais vous verrez que la notification “x applications Android s’exécutent en arrière-plan”.

Bloquer la notification de service de premier plan

À partir d’Android 7.1, il ne semble pas y avoir de trucs ou de bogues à ce sujet. Au lieu de cela, vous devez indiquer à l’utilisateur de désactiver votre notification de service de premier plan dans les parameters d’Android.

Comment

Android 4.1 à 7.1 (inclus)

Je crois que le seul moyen est de désactiver toutes les notifications de votre application.

  1. Utilisez l’intention d’envoyer l’utilisateur à l’écran de détails de votre application:

     Uri uri = Uri.fromParts("package", getPackageName(), null); Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(uri); startActivity(intent); 
  2. Ensuite, l’utilisateur doit bloquer les notifications de l’application à partir de là.

Notez que cela bloque également les toasts de votre application.

Android 8:

Malheureusement, si l’utilisateur bloque la notification de service, Android le remplacera par une notification ” {App name} s’exécute en arrière-plan “. Donc, il ne sert à rien de le cacher.

Voici un moyen de rendre oom_adj de votre application à 1 (testé dans l’émulateur SDK ANDROID 6.0). Ajoutez un service temporaire, dans votre appel de service principal, startForgroundService(NOTIFICATION_ID, notificion) . Et puis, lancez à nouveau l’appel de service temporaire startForgroundService(NOTIFICATION_ID, notificion) avec le même identifiant de notification, après un certain temps dans l’appel de service temporaire stopForgroundService (true) pour rejeter l’ontification en cours.

J’ai développé un lecteur multimédia simple il y a quelques mois. Donc, ce que je crois, c’est que si vous faites quelque chose comme:

 Intent i = new Intent(this, someServiceclass.class); 

startService (i);

Ensuite, le système ne devrait pas pouvoir tuer votre service.

référence : lisez le paragraphe qui discute quand le système arrête le service

Vous pouvez également déclarer votre application comme persistante.

   

Cela définit essentiellement votre application à une priorité de mémoire plus élevée, ce qui diminue la probabilité qu’elle soit supprimée.