Je veux créer un service et le faire fonctionner au premier plan.
La plupart des exemples de codes comportent des notifications. Mais je ne veux afficher aucune notification. Est-ce possible?
Pouvez-vous me donner quelques exemples? Existe-t-il des alternatives?
Mon service d'application utilise Mediaplayer. Comment faire en sorte que le système ne tue pas mon service sauf que l'application le tue elle-même (comme mettre en pause ou arrêter la musique par bouton).
android
android-service
foreground
Muhammad Resna Rizki Pratama
la source
la source
Réponses:
En tant que fonction de sécurité de la plate-forme Android, vous ne pouvez en aucun cas avoir un service au premier plan sans avoir également une notification. En effet, un service au premier plan consomme une plus grande quantité de ressources et est soumis à des contraintes de planification différentes (c'est-à-dire qu'il n'est pas tué aussi rapidement) que les services d'arrière-plan, et l'utilisateur a besoin de savoir ce qui peut manger sa batterie. 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). C'est extrêmement malhonnête pour vos utilisateurs et vous n'avez aucune raison de le faire, à part tuer leur batterie et créer ainsi des logiciels malveillants.
la source
Mise à jour: cela 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 pratiquement impossible de démarrer un service avec
startForeground()
sans afficher de notification.Vous pouvez cependant masquer l'icône à l'aide des API officielles ... pas besoin d'icône transparente: (à utiliser
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 quiconque veut toujours la cacher, j'ai peut-être trouvé une solution de contournement pour cela aussi:
startForeground()
avec la notification et tout.startForeground()
(même ID de notification)stopSelf()
et appeler onDestroystopForeground(true)
).Voilà! Aucune notification du tout et votre deuxième service continue de fonctionner.
la source
Cela ne fonctionne plus à partir d'Android 7.1 et peut enfreindre les politiques des développeurs de Google Play .
Au lieu de cela, demandez à l'utilisateur de bloquer la notification de service .
Voici ma mise en œuvre de la technique dans la réponse de Lior Iluz .
Code
ForegroundService.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; } }
ForegroundEnablingService.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
<service android:name=".ForegroundEnablingService" /> <service android:name=".ForegroundService" />
Compatibilité
Testé et travaille sur:
Ne fonctionne plus depuis Android 7.1.
la source
ForegroundService
Vous pouvez utiliser ceci (comme suggéré par @Kristopher Micinski):
Notification note = new Notification( 0, null, System.currentTimeMillis() ); note.flags |= Notification.FLAG_NO_CLEAR; startForeground( 42, note );
MISE À JOUR:
Veuillez noter que cela 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 en arrière-plan visibles pour les utilisateurs, comme mentionné par @Kristopher Micinski
la source
Attention : bien que cette réponse semble fonctionner, elle empêche en fait silencieusement votre service de devenir un service de premier plan .
Réponse originale:
Définissez simplement l'ID de votre notification sur 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 que le système
Service
sera capable de fonctionner en haute priorité sans être détruit par le système Android, sauf en cas de forte pression de la mémoire.ÉDITER
Pour le faire fonctionner avec Pre-Honeycomb et Android 4.4 et versions ultérieures, assurez-vous d'utiliser
NotificationCompat.Builder
celui fourni par Support Library v7, au lieu deNotification.Builder
.la source
Notification.Builder
, Support Library v4NotificationCompat.Builder
et Support Library v7NotificationCompat.Builder
. La notification n'apparaissait pas dans le tiroir de notification ou la barre d'état, mais le service ne fonctionnait pas en mode de premier plan lorsque je l'ai vérifié à l'aide degetRunningServices()
etdumpsys
.adb shell dumpsys activity services
pour vérifier.Vous pouvez masquer la notification sur Android 9+ en utilisant une mise en page personnalisée avec layout_height = "0dp"
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, NotificationUtils.CHANNEL_ID); RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.custom_notif); builder.setContent(remoteViews); builder.setPriority(NotificationCompat.PRIORITY_LOW); builder.setVisibility(Notification.VISIBILITY_SECRET);
custom_notif.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="0dp"> </LinearLayout>
Testé sur Pixel 1, Android 9. Cette solution ne fonctionne pas sur Android 8 ou moins
la source
Mise à jour: cela ne fonctionne plus sous Android 4.3 et supérieur
Il existe une solution de contournement. Essayez de créer une notification sans icône de réglage et la notification ne s'afficherait 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 source
(YourServiceName) is running
notification au lieu de la vôtre lorsque vous ne spécifiez pas d'icône. Selon CommonsWare, c'est le cas depuis Android 4.3: commonsware.com/blog/2013/07/30Mise à jour: cela ne fonctionne plus sous Android 4.3 et supérieur
J'ai défini le paramètre icon du constructeur pour Notification sur zéro, puis j'ai passé la notification résultante à startForeground (). Aucune erreur dans le journal et aucune notification n'apparaît. Je ne sais pas, cependant, si le service a été mis en avant avec succès - y a-t-il un moyen de vérifier?
Modifié: vérifié avec dumpsys, et en effet le service est au premier plan sur mon système 2.3. Je n'ai pas encore vérifié avec d'autres versions du système d'exploitation.
la source
Notification()
constructeur vide .Bloquer la notification de service de premier plan
La plupart des réponses ici ne fonctionnent pas, interrompent le service de premier plan ou enfreignent les règles de Google Play .
La seule façon de masquer la notification de manière fiable et sûre est de la bloquer par l'utilisateur.
Android 4.1 - 7.1
Le seul moyen est de bloquer toutes les notifications de votre application:
Envoyer l'utilisateur à l'écran des détails de l'application:
Uri uri = Uri.fromParts("package", getPackageName(), null); Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(uri); startActivity(intent);
Faire bloquer les notifications de l'application par l'utilisateur
Notez que cela bloque également les toasts de votre application.
Android 8,0 à 8,1
Cela ne vaut pas la peine de bloquer la notification sur Android O car le système d'exploitation la remplacera simplement par une notification " en arrière-plan " ou "en utilisant la batterie ".
Android 9+
Utilisez un canal de notification pour bloquer la notification de service sans affecter vos autres notifications.
Envoyer l'utilisateur aux paramètres du canal de notification
Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS) .putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName()) .putExtra(Settings.EXTRA_CHANNEL_ID, myNotificationChannel.getId()); startActivity(intent);
Faire bloquer les notifications de la chaîne par l'utilisateur
la source
la version 4.3 (18) et au-dessus de cacher la notification de service n'est pas possible, mais vous pouvez désactiver l'icône, la version 4.3 (18) et ci-dessous est possible pour cacher la notification
Notification noti = new Notification(); if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) { noti.priority = Notification.PRIORITY_MIN; } startForeground(R.string.app_name, noti);
la source
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 n'est pas affichée, mais vous verrez la notification Android 'x applications s'exécutant en arrière-plan'.
la source
apps are running in the background
notification est encore pire qu'une notification spécifique à une application, donc je ne suis pas sûr que cette approche en vaille la peine.Mise à jour: cela ne fonctionne plus sous Android 7.1 et supérieur
Voici un moyen de rendre oom_adj de votre application à 1 (Testé dans l'émulateur du SDK ANDROID 6.0).Ajoutez un service temporaire, dans votre appel de service principal
startForgroundService(NOTIFICATION_ID, notificion)
. Et puis redémarrez l'appel de service temporairestartForgroundService(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.la source
Vous pouvez également déclarer votre application comme persistante.
<application android:icon="@drawable/icon" android:label="@string/app_name" android:theme="@style/Theme" *android:persistent="true"* > </application>
Cela définit essentiellement votre application sur une priorité de mémoire plus élevée, ce qui réduit la probabilité qu'elle soit supprimée.
la source
J'ai développé un simple lecteur multimédia 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 être en mesure de tuer votre service.
référence : lisez le paragraphe qui traite du moment où le système arrête le service
la source