Ich möchte einen Dienst erstellen und ihn in den Vordergrund stellen.
Die meisten Beispielcodes enthalten Benachrichtigungen. Ich möchte aber keine Benachrichtigung anzeigen. Ist das möglich?
Können Sie mir einige Beispiele geben? Gibt es Alternativen?
Mein App-Service macht Mediaplayer. Wie man das System dazu bringt, meinen Dienst nicht zu beenden, außer dass die App ihn selbst beendet (wie das Anhalten oder Stoppen der Musik per Taste).
android
android-service
foreground
Muhammad Resna Rizki Pratama
quelle
quelle
Antworten:
Als Sicherheitsmerkmal der Android - Plattform, Sie können nicht unter jedem Umstand, haben einen Vordergrund Dienst ohne eine Benachrichtigung mit. Dies liegt daran, dass ein Vordergrunddienst eine größere Menge an Ressourcen verbraucht und anderen Planungsbeschränkungen unterliegt (dh nicht so schnell beendet wird) als Hintergrunddienste, und der Benutzer muss wissen, was möglicherweise seine Batterie verbraucht. Also tu das nicht .
Es ist jedoch möglich, eine "gefälschte" Benachrichtigung zu erhalten, dh Sie können ein transparentes Benachrichtigungssymbol (iirc) erstellen. Dies ist für Ihre Benutzer äußerst unaufrichtig, und Sie haben keinen Grund, dies zu tun, außer den Akku zu leeren und damit Malware zu erstellen.
quelle
Update: Dies wurde unter Android 7.1 "behoben". https://code.google.com/p/android/issues/detail?id=213309
Seit dem 4.3-Update ist es grundsätzlich unmöglich , einen Dienst
startForeground()
ohne Benachrichtigung zu starten .Sie können das Symbol jedoch mithilfe offizieller APIs ausblenden. Es ist kein transparentes Symbol erforderlich: (
NotificationCompat
Zur Unterstützung älterer Versionen)NotificationCompat.Builder builder = new NotificationCompat.Builder(context); builder.setPriority(Notification.PRIORITY_MIN);
Ich habe mich damit abgefunden, dass die Benachrichtigung selbst noch vorhanden sein muss, aber für jeden, der sie noch verbergen möchte, habe ich möglicherweise auch eine Problemumgehung gefunden:
startForeground()
mit der Benachrichtigung und allem.startForeground()
(derselben Benachrichtigungs-ID)stopSelf()
Beenden Sie den ersten (gefälschten) Dienst (Sie können anrufen und onDestroy anrufenstopForeground(true)
).Voilà! Überhaupt keine Benachrichtigung und Ihr zweiter Dienst läuft weiter.
quelle
Dies funktioniert ab Android 7.1 nicht mehr und verstößt möglicherweise gegen die Entwicklerrichtlinien von Google Play .
Lassen Sie den Benutzer stattdessen die Dienstbenachrichtigung blockieren .
Hier ist meine Implementierung der Technik in der Antwort von 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" />
Kompatibilität
Getestet und bearbeitet an:
Ab Android 7.1 funktioniert es nicht mehr.
quelle
ForegroundService
Sie können dies verwenden (wie von @Kristopher Micinski vorgeschlagen):
Notification note = new Notification( 0, null, System.currentTimeMillis() ); note.flags |= Notification.FLAG_NO_CLEAR; startForeground( 42, note );
AKTUALISIEREN:
Bitte beachten Sie, dass dies mit Android KitKat + -Versionen nicht mehr zulässig ist. Und denken Sie daran, dass dies mehr oder weniger gegen das Designprinzip in Android verstößt, das Hintergrundvorgänge für Benutzer sichtbar macht, wie von @Kristopher Micinski erwähnt
quelle
Warnung : Obwohl diese Antwort zu funktionieren scheint, verhindert sie stillschweigend, dass Ihr Dienst zu einem Vordergrunddienst wird .
Ursprüngliche Antwort:
Setzen Sie einfach die ID Ihrer Benachrichtigung auf Null:
// 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); ...
Ein Vorteil, den Sie erhalten können, ist, dass a
Service
mit hoher Priorität ausgeführt werden kann, ohne vom Android-System zerstört zu werden, es sei denn, es liegt ein hoher Speicherdruck vor.BEARBEITEN
Stellen Sie sicher, dass Sie
NotificationCompat.Builder
anstelle von Pre-Honeycomb und Android 4.4 und höher das von Support Library v7 bereitgestellte verwendenNotification.Builder
.quelle
Notification.Builder
, Support Library v4NotificationCompat.Builder
und Support Library v7NotificationCompat.Builder
. Die Benachrichtigung wurde nicht in der Benachrichtigungsleiste oder in der Statusleiste angezeigt, aber der Dienst wurde nicht im Vordergrundmodus ausgeführt, als ich ihn mitgetRunningServices()
und überprüft habedumpsys
.adb shell dumpsys activity services
zur Überprüfung.Sie können Benachrichtigungen unter Android 9+ ausblenden, indem Sie ein benutzerdefiniertes Layout mit layout_height = "0dp" verwenden.
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>
Getestet auf Pixel 1, Android 9. Diese Lösung funktioniert nicht auf Android 8 oder weniger
quelle
Update: Dies funktioniert nicht mehr in Android 4.3 und höher
Es gibt eine Problemumgehung. Versuchen Sie, eine Benachrichtigung zu erstellen, ohne das Symbol festzulegen, und die Benachrichtigung wird nicht angezeigt. Ich weiß nicht wie es funktioniert, aber es funktioniert :)
Notification notification = new NotificationCompat.Builder(this) .setContentTitle("Title") .setTicker("Title") .setContentText("App running") //.setSmallIcon(R.drawable.picture) .build(); startForeground(101, notification);
quelle
(YourServiceName) is running
Benachrichtigung anstelle Ihrer eigenen an, wenn Sie kein Symbol angeben. Laut CommonsWare ist dies seit Android 4.3 der Fall: commonsware.com/blog/2013/07/30/…Update: Dies funktioniert nicht mehr in Android 4.3 und höher
Ich habe den Parameter icon auf den Konstruktor für Notification auf Null gesetzt und dann die resultierende Benachrichtigung an startForeground () übergeben. Es werden keine Fehler im Protokoll und keine Benachrichtigung angezeigt. Ich weiß jedoch nicht, ob der Dienst erfolgreich in den Vordergrund gestellt wurde - gibt es eine Möglichkeit, dies zu überprüfen?
Bearbeitet: Mit dumpsys überprüft, und tatsächlich steht der Dienst auf meinem 2.3-System im Vordergrund. Ich habe noch keine Überprüfung mit anderen Betriebssystemversionen durchgeführt.
quelle
Notification()
Konstruktor auf.Blockieren Sie die Vordergrunddienstbenachrichtigung
Die meisten Antworten hier funktionieren entweder nicht, unterbrechen den Vordergrunddienst oder verstoßen gegen die Google Play-Richtlinien .
Die einzige Möglichkeit, die Benachrichtigung zuverlässig und sicher auszublenden, besteht darin, sie vom Benutzer blockieren zu lassen.
Android 4.1 - 7.1
Die einzige Möglichkeit besteht darin, alle Benachrichtigungen aus Ihrer App zu blockieren :
Benutzer zum Detailbildschirm der App senden:
Uri uri = Uri.fromParts("package", getPackageName(), null); Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(uri); startActivity(intent);
Lassen Sie die Benachrichtigungen der Benutzer-App blockieren
Beachten Sie, dass dies auch die Toasts Ihrer App blockiert.
Android 8.0 - 8.1
Es lohnt sich nicht, die Benachrichtigung unter Android O zu blockieren, da das Betriebssystem sie lediglich durch " Laufen im Hintergrund " oder " Verwenden des Akkus" ersetzt Benachrichtigung " ersetzt.
Android 9+
Verwenden Sie einen Benachrichtigungskanal , um die Dienstbenachrichtigung zu blockieren, ohne Ihre anderen Benachrichtigungen zu beeinflussen.
Benutzer an die Einstellungen des Benachrichtigungskanals senden
Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS) .putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName()) .putExtra(Settings.EXTRA_CHANNEL_ID, myNotificationChannel.getId()); startActivity(intent);
Lassen Sie die Benachrichtigungen des Benutzerkanals blockieren
quelle
Version 4.3 (18) und höher Das Ausblenden von Dienstbenachrichtigungen ist nicht möglich. Sie können jedoch das Symbol deaktivieren. Version 4.3 (18) und niedriger können die Benachrichtigung ausblenden
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);
quelle
Ich habe unter Android 8.0 festgestellt, dass es immer noch möglich ist, keinen Benachrichtigungskanal zu verwenden.
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 { //... } } } }
Und in 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); } }
Eine dauerhafte Benachrichtigung wird nicht angezeigt. Sie sehen jedoch, dass die Android-Benachrichtigungen "x Apps werden im Hintergrund ausgeführt".
quelle
apps are running in the background
Benachrichtigung noch schlechter ist als eine app-spezifische Benachrichtigung, daher bin ich mir nicht sicher, ob sich dieser Ansatz lohnt.Update: Dies funktioniert nicht mehr in Android 7.1 und höher
Hier ist eine Möglichkeit, oom_adj Ihrer App auf 1 zu setzen (getestet im ANDROID 6.0 SDK-Emulator).Fügen Sie einen temporären Dienst hinzu. In Ihrem Hauptdienstanruf
startForgroundService(NOTIFICATION_ID, notificion)
. Starten Sie dann den temporären ServiceabrufstartForgroundService(NOTIFICATION_ID, notificion)
mit derselben Benachrichtigungs-ID erneut, nach einer Weile im temporären Serviceaufruf stopForgroundService (true), um die fortlaufende Ontifizierung zu schließen.quelle
Sie können Ihre Anwendung auch als dauerhaft deklarieren.
<application android:icon="@drawable/icon" android:label="@string/app_name" android:theme="@style/Theme" *android:persistent="true"* > </application>
Dadurch wird Ihre App im Wesentlichen auf eine höhere Speicherpriorität eingestellt, wodurch die Wahrscheinlichkeit verringert wird, dass sie getötet wird.
quelle
Ich habe vor ein paar Monaten einen einfachen Media Player entwickelt. Ich glaube also, wenn Sie so etwas tun:
Intent i = new Intent(this, someServiceclass.class);
startService (i);
Dann sollte das System Ihren Dienst nicht beenden können.
Referenz : Lesen Sie den Abschnitt, in dem erläutert wird, wann das System den Dienst beendet
quelle