Я хочу создать службу и заставить ее работать на переднем плане.
На большинстве примеров кодов есть уведомления. Но я не хочу показывать никаких уведомлений. Это возможно?
Вы можете привести мне несколько примеров? Есть ли альтернативы?
Моя служба приложений делает медиаплеер. Как сделать так, чтобы система не убивала мою службу, за исключением того, что приложение убивает ее само (например, приостанавливает или останавливает музыку кнопкой).
android
android-service
foreground
Мухаммад Ресна Ризки Пратама
источник
источник
Ответы:
В качестве функции безопасности платформы Android вы ни при каких обстоятельствах не можете использовать передовую службу без уведомления. Это связано с тем, что передовая служба потребляет больше ресурсов и подчиняется другим ограничениям планирования (т. Е. Она не прекращается так быстро), чем фоновые службы, и пользователю необходимо знать, что, возможно, съедает их батарею. Так что не делай этого.
Тем не менее, это возможно , чтобы иметь «поддельное» уведомление, то есть вы можете сделать прозрачный значок уведомления (IIRC). Это крайне неискренне по отношению к вашим пользователям, и у вас нет причин для этого, кроме как убивать их батареи и тем самым создавать вредоносные программы.
источник
Обновление: это было «исправлено» на Android 7.1. https://code.google.com/p/android/issues/detail?id=213309
После обновления 4.3 практически невозможно запустить службу
startForeground()
без отображения уведомления.Однако вы можете скрыть значок с помощью официальных API-интерфейсов ... прозрачный значок не нужен: (Используйте
NotificationCompat
для поддержки более старых версий)NotificationCompat.Builder builder = new NotificationCompat.Builder(context); builder.setPriority(Notification.PRIORITY_MIN);
Я смирился с тем фактом, что само уведомление все еще должно быть там, но для тех, кто все еще хочет скрыть его, я, возможно, нашел обходной путь и для этого:
startForeground()
уведомлением и всем остальным.startForeground()
(тот же идентификатор уведомления)stopSelf()
и в onDestroy callstopForeground(true)
).Вуаля! Уведомлений нет вообще, и ваша вторая служба продолжает работать.
источник
Это больше не работает с Android 7.1 и может нарушать политику разработчиков Google Play .
Вместо этого попросите пользователя заблокировать служебное уведомление .
Вот моя реализация техники в ответ по Лиор Iluz .
Код
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; } }
ForegroundEnhibitedService.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" />
Совместимость
Проверено и работает:
Больше не работает с Android 7.1.
источник
ForegroundService
Вы можете использовать это (как предлагает @Kristopher Micinski):
Notification note = new Notification( 0, null, System.currentTimeMillis() ); note.flags |= Notification.FLAG_NO_CLEAR; startForeground( 42, note );
ОБНОВИТЬ:
Обратите внимание, что это больше не разрешено в версиях Android KitKat +. И имейте в виду, что это более или менее нарушает принцип дизайна в Android, который делает фоновые операции видимыми для пользователей, как упомянул @Kristopher Micinski.
источник
Предупреждение : хотя этот ответ, похоже, работает, на самом деле он молча предотвращает превращение вашей службы в службу переднего плана .
Оригинальный ответ:
Просто установите идентификатор вашего уведомления равным нулю:
// 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); ...
Преимущество, которое вы можете получить, заключается в том,
Service
что он сможет работать с высоким приоритетом без разрушения системой Android, если не будет высокой нагрузки на память.РЕДАКТИРОВАТЬ
Чтобы он работал с Pre-Honeycomb и Android 4.4 и выше, убедитесь, что вы используете то,
NotificationCompat.Builder
что предоставлено библиотекой поддержки v7, а неNotification.Builder
.источник
Notification.Builder
, Support Library v4NotificationCompat.Builder
и Support Library v7NotificationCompat.Builder
. Уведомление не отображалось в панели уведомлений или строке состояния, но служба не работала в режиме переднего плана, когда я проверял ее с помощьюgetRunningServices()
иdumpsys
.adb shell dumpsys activity services
для проверки.Вы можете скрыть уведомление на Android 9+ , используя настраиваемый макет с 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>
Проверено на Pixel 1, android 9. Это решение не работает на Android 8 или более ранней версии.
источник
Обновление: это больше не работает в Android 4.3 и выше.
Есть одно решение. Попробуйте создать уведомление без настройки значка, и уведомление не будет отображаться. Не знаю, как это работает, но работает :)
Notification notification = new NotificationCompat.Builder(this) .setContentTitle("Title") .setTicker("Title") .setContentText("App running") //.setSmallIcon(R.drawable.picture) .build(); startForeground(101, notification);
источник
(YourServiceName) is running
уведомление вместо вашего, если вы не укажете значок. Согласно CommonsWare, это было так, начиная с Android 4.3: commonsware.com/blog/2013/07/30/…Обновление: это больше не работает в Android 4.3 и выше.
Я установил параметр значка в конструкторе для уведомления равным нулю, а затем передал полученное уведомление в startForeground (). Никаких ошибок в журнале и никаких уведомлений не появляется. Однако я не знаю, была ли эта услуга успешной - есть ли возможность проверить?
Отредактировано: Проверено с помощью dumpsys, и действительно, эта служба основана на моей системе 2.3. Еще не проверял с другими версиями ОС.
источник
Notification()
конструктор.Блокировать уведомление службы переднего плана
Большинство ответов здесь либо не работают , либо нарушают службу переднего плана , либо нарушают политику Google Play .
Единственный способ надежно и безопасно скрыть уведомление - это заблокировать его пользователем.
Android 4.1–7.1
Единственный способ - заблокировать все уведомления от вашего приложения:
Отправить пользователя на экран сведений о приложении:
Uri uri = Uri.fromParts("package", getPackageName(), null); Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(uri); startActivity(intent);
Попросите пользователя заблокировать уведомления приложения
Обратите внимание, что это также блокирует тосты вашего приложения.
Android 8.0–8.1
Не стоит блокировать уведомление на Android O, потому что ОС просто заменит его на уведомление « работает в фоновом режиме » или « использует аккумулятор ».
Android 9+
Используйте канал уведомлений, чтобы заблокировать служебное уведомление, не влияя на другие уведомления.
Отправить пользователя в настройки канала уведомлений
Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS) .putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName()) .putExtra(Settings.EXTRA_CHANNEL_ID, myNotificationChannel.getId()); startActivity(intent);
Попросите пользователя заблокировать уведомления канала
источник
Версия 4.3 (18) и выше скрыть служебное уведомление невозможно, но вы можете отключить значок, версия 4.3 (18) и ниже позволяет скрыть уведомление
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);
источник
Я обнаружил, что на Android 8.0 это все еще возможно, не используя канал уведомлений.
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 { //... } } } }
И в 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); } }
Постоянное уведомление не отображается, однако вы увидите уведомление «x-приложения Android работают в фоновом режиме».
источник
apps are running in the background
уведомление даже хуже, чем уведомление для конкретного приложения, поэтому я не уверен, что такой подход того стоит.Обновление: это больше не работает в Android 7.1 и выше.
Вот способ сделать oom_adj вашего приложения равным 1 (протестировано в эмуляторе SDK ANDROID 6.0).Добавьте временную службу в основной вызов службы
startForgroundService(NOTIFICATION_ID, notificion)
. А затем снова запустите вызов временной службыstartForgroundService(NOTIFICATION_ID, notificion)
с тем же идентификатором уведомления, через некоторое время во временном вызове службы stopForgroundService (true), чтобы отклонить начальную онтификацию.источник
Вы также можете объявить свое приложение постоянным.
<application android:icon="@drawable/icon" android:label="@string/app_name" android:theme="@style/Theme" *android:persistent="true"* > </application>
По сути, это устанавливает для вашего приложения более высокий приоритет памяти, что снижает вероятность его закрытия.
источник
Пару месяцев назад я разработал простой медиаплеер. Я считаю, что если вы делаете что-то вроде:
Intent i = new Intent(this, someServiceclass.class);
startService (я);
Тогда система не сможет убить вашу службу.
ссылка : прочтите параграф, в котором обсуждается, когда система останавливает службу
источник