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 montrer aucune notification. Est-ce possible?
Pouvez-vous me donner des exemples? Y a-t-il des alternatives?
Mon service d'application est en train de faire mediaplayer. Comment faire en sorte que le système ne tue pas mon service sauf que l'application le tue lui-même (comme mettre en pause ou arrêter la musique avec un bouton).
En tant que fonction de sécurité de la plate-forme Android, vous ne pouvez pas , sous aucune , disposez d’un service de premier plan sans notification préalable, car un service de premier plan consomme une quantité de ressources plus importante et est soumis à différentes contraintes de planification (c’est-à-dire qu’il n’est pas tué rapidement) que les services d'arrière-plan et que l'utilisateur a besoin de savoir ce qui lui est imposé par sa batterie, donc ne le faites pas .
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 hypocrite pour vos utilisateurs, et vous n'avez aucune raison de le faire, si ce n'est de tuer leur batterie et de créer ainsi un malware.
Mise à jour: Ceci a été "corrigé" le 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 toutefois masquer l'icône à l'aide des API officielles ... inutile d'utiliser une icône transparente: (utilisez NotificationCompat
pour prendre en charge les versions antérieures)
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 que ce soit qui veuille encore la cacher, j'ai peut-être trouvé une solution de contournement à cela:
startForeground()
avec la notification et tout le reste.startForeground()
(même ID de notification)stopSelf()
et dans l'appel onDestroy stopForeground(true)
).Voilà! Aucune notification du tout et votre deuxième service continue à fonctionner.
Cela ne fonctionne plus à partir de Android 7.1 et cela pourrait enfreindre règles de développement de Google Play .
Au lieu de cela, je suggère ayant l'utilisateur bloque la notification de service .
Voici ma mise en œuvre de la technique dans la réponse par Lior Iluz .
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;
}
}
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;
}
}
<service Android:name=".ForegroundEnablingService" />
<service Android:name=".ForegroundService" />
Testé et travaillant sur:
Ne fonctionne plus à partir de Android 7.1.
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 );
PDATE:
Veuillez noter que cela n'est plus autorisé avec les versions Android de KitKat +. Et gardez à l'esprit que cela enfreint plus ou moins le principe de conception de Android qui crée un arrière-plan opérations visibles par les utilisateurs, mentionnées par @Kristopher Micinski
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 des avantages que vous pouvez obtenir est qu'un Service
pourra fonctionner en priorité élevée sans être détruit par le système Android, sauf en cas de forte pression de la mémoire.
EDIT
Pour que cela fonctionne avec Pre-Honeycomb et Android 4.4 et versions supérieures, assurez-vous d’utiliser NotificationCompat.Builder
fourni par Support Library v7 au lieu de Notification.Builder
.
Il existe une solution de contournement. Essayez de créer une notification sans configurer l'icône, 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);
J'ai mis le paramètre icon au constructeur de Notification pour Notification à zéro, puis j'ai transmis la notification résultante à startForeground (). Aucune erreur dans le journal et aucune notification ne s'affiche. Je ne sais toutefois pas si le service a été mis en avant avec succès. Existe-t-il un moyen de vérifier?
Édité: Vérifié avec dumpsys, et le service est mis en avant sur mon système 2.3. Je n'ai pas encore vérifié avec les autres versions du système d'exploitation.
Vous pouvez masquer la notification sur Android 9 en utilisant une disposition 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
J'ai trouvé sur Android 8.0, il est toujours possible de ne pas utiliser un 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 la notification Android "Les applications sont exécutées en arrière-plan".
Android 7.1+ ne peut pas être exploité pour masquer la notification. Au lieu de cela, demandez à l'utilisateur de le bloquer.
Le seul moyen est de bloquer toutes les notifications de votre application:
Envoyer l'utilisateur à l'écran de 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);
Avoir les notifications de l'application utilisateur de blocage
Notez que ceci bloque également les toasts de votre application.
Il ne vaut pas la peine de bloquer la notification sur Android O car le système d'exploitation ne la remplace que par un " s'exécute en arrière-plan" ou " avec batterie "notification.
Utilisez un Notification Channel pour bloquer uniquement la notification de service.
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);
Avoir les notifications des canaux bloqués par l'utilisateur
il est impossible de masquer la notification de service dans les versions 4.3 (18) et supérieures, mais vous pouvez désactiver l'icône. La version 4.3 (18) et les versions ultérieures permettent 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.string.app_name, noti);