Quiero crear un servicio y hacerlo funcionar en primer plano.
La mayoría de los códigos de ejemplo tienen notificaciones. Pero no quiero mostrar ninguna notificación. ¿Es eso posible?
¿Me puede dar algunos ejemplos? ¿Existen alternativas?
Mi servicio de aplicaciones está haciendo mediaplayer. Cómo hacer que el sistema no elimine mi servicio, excepto que la aplicación lo elimine por sí misma (como pausar o detener la música con un botón).
android
android-service
foreground
Muhammad Resna Rizki Pratama
fuente
fuente
Respuestas:
Como característica de seguridad de la plataforma Android, no puede , bajo ninguna circunstancia, tener un servicio en primer plano sin tener también una notificación. Esto se debe a que un servicio en primer plano consume una mayor cantidad de recursos y está sujeto a diferentes restricciones de programación (es decir, no se elimina tan rápido) que los servicios en segundo plano, y el usuario debe saber qué es lo que posiblemente esté consumiendo su batería. Entonces, no hagas esto.
De todos modos, eso es posible tener una notificación "falsa", es decir, puede crear un icono de notificación transparente (iirc). Esto es extremadamente falso para sus usuarios y no tiene ninguna razón para hacerlo, aparte de matar su batería y, por lo tanto, crear malware.
fuente
Actualización: esto se "solucionó" en Android 7.1. https://code.google.com/p/android/issues/detail?id=213309
Desde la actualización 4.3, es básicamente imposible iniciar un servicio
startForeground()
sin mostrar una notificación.Sin embargo, puede ocultar el icono utilizando las API oficiales ... no es necesario un icono transparente: (Úselo
NotificationCompat
para admitir versiones anteriores)NotificationCompat.Builder builder = new NotificationCompat.Builder(context); builder.setPriority(Notification.PRIORITY_MIN);
He hecho las paces con el hecho de que la notificación en sí todavía debe estar allí, pero para quien quiera ocultarla, es posible que también haya encontrado una solución para eso:
startForeground()
con la notificación y todo.startForeground()
(mismo ID de notificación)stopSelf()
y en onDestroy llamarstopForeground(true)
).¡Voilà! Sin notificación en absoluto y su segundo servicio sigue funcionando.
fuente
Esto ya no funciona a partir de Android 7.1 y puede violar las políticas para desarrolladores de Google Play .
En su lugar, haga que el usuario bloquee la notificación de servicio .
Aquí está mi implementación de la técnica en la respuesta de Lior Iluz .
Código
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" />
Compatibilidad
Probado y trabajando en:
Ya no funciona a partir de Android 7.1.
fuente
ForegroundService
Puede usar esto (como lo sugiere @Kristopher Micinski):
Notification note = new Notification( 0, null, System.currentTimeMillis() ); note.flags |= Notification.FLAG_NO_CLEAR; startForeground( 42, note );
ACTUALIZAR:
Tenga en cuenta que esto ya no está permitido con las versiones de Android KitKat +. Y tenga en cuenta que esto viola más o menos el principio de diseño en Android que hace que las operaciones en segundo plano sean visibles para los usuarios, como lo menciona @Kristopher Micinski.
fuente
Advertencia : aunque esta respuesta parece funcionar, de hecho evita silenciosamente que su servicio se convierta en un servicio en primer plano .
Respuesta original:
Simplemente establezca el ID de su notificación en cero:
// 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 beneficio que puede obtener es un
Service
que podrá ejecutarse en alta prioridad sin ser destruido por el sistema Android, a menos que haya mucha presión de memoria.EDITAR
Para que funcione con Pre-Honeycomb y Android 4.4 y superior, asegúrese de utilizar el
NotificationCompat.Builder
que proporciona Support Library v7, en lugar deNotification.Builder
.fuente
Notification.Builder
, Support Library v4NotificationCompat.Builder
y Support Library v7NotificationCompat.Builder
. La notificación no apareció en el cajón de notificaciones o en la barra de estado, pero el servicio no se estaba ejecutando en modo de primer plano cuando lo verifiqué usandogetRunningServices()
ydumpsys
.adb shell dumpsys activity services
para verificar.Puede ocultar la notificación en Android 9+ usando un diseño personalizado con 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>
Probado en Pixel 1, Android 9. Esta solución no funciona en Android 8 o menos
fuente
Actualización: esto ya no funciona en Android 4.3 y superior
Hay una solución. Intente crear una notificación sin configurar el icono y la notificación no se mostrará. No sé cómo funciona, pero funciona :)
Notification notification = new NotificationCompat.Builder(this) .setContentTitle("Title") .setTicker("Title") .setContentText("App running") //.setSmallIcon(R.drawable.picture) .build(); startForeground(101, notification);
fuente
(YourServiceName) is running
notificación en lugar de la suya propia cuando no especifica un icono. Según CommonsWare, este ha sido el caso desde Android 4.3: commonsware.com/blog/2013/07/30/…Actualización: esto ya no funciona en Android 4.3 y superior
Establecí el parámetro de icono en el constructor para Notificación en cero, y luego pasé la notificación resultante a startForeground (). No hay errores en el registro y no aparece ninguna notificación. Sin embargo, no sé si el servicio se puso en primer plano correctamente. ¿Hay alguna forma de comprobarlo?
Editado: verificado con dumpsys, y de hecho el servicio está en primer plano en mi sistema 2.3. Aún no he comprobado con otras versiones del sistema operativo.
fuente
Notification()
constructor vacío .Bloquear la notificación del servicio en primer plano
La mayoría de las respuestas aquí no funcionan, interrumpen el servicio de primer plano o violan las políticas de Google Play .
La única forma de ocultar la notificación de manera confiable y segura es hacer que el usuario la bloquee.
Android 4.1 - 7.1
La única forma es bloquear todas las notificaciones de su aplicación:
Envíe al usuario a la pantalla de detalles de la aplicación:
Uri uri = Uri.fromParts("package", getPackageName(), null); Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(uri); startActivity(intent);
Hacer que el usuario bloquee las notificaciones de la aplicación
Tenga en cuenta que esto también bloquea los brindis de su aplicación.
Android 8.0 - 8.1
No vale la pena bloquear la notificación en Android O porque el sistema operativo simplemente la reemplazará con una " ejecución en segundo plano " o " usando batería notificación de ".
Android 9+
Utilice un canal de notificación para bloquear la notificación de servicio sin afectar sus otras notificaciones.
Enviar al usuario a la configuración del canal de notificación
Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS) .putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName()) .putExtra(Settings.EXTRA_CHANNEL_ID, myNotificationChannel.getId()); startActivity(intent);
Hacer que el usuario bloquee las notificaciones del canal.
fuente
versión 4.3 (18) y superior, no es posible ocultar la notificación del servicio, pero puede deshabilitar el icono, la versión 4.3 (18) y las siguientes pueden ocultar la notificación
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);
fuente
Descubrí que en Android 8.0 todavía es posible sin usar un canal de notificación.
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 { //... } } } }
Y en 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); } }
No se muestra una notificación persistente, sin embargo, verá la notificación de Android 'x aplicaciones se están ejecutando en segundo plano'.
fuente
apps are running in the background
notificación es incluso peor que una notificación específica de la aplicación, por lo que no estoy seguro de que este enfoque valga la pena.Actualización: esto ya no funciona en Android 7.1 y superior
Aquí hay una manera de hacer que el oom_adj de su aplicación sea 1 (probado en el emulador SDK de ANDROID 6.0).Agregue un servicio temporal, en su llamada de servicio principal
startForgroundService(NOTIFICATION_ID, notificion)
. Y luego inicie la llamada de servicio temporalstartForgroundService(NOTIFICATION_ID, notificion)
con la misma identificación de notificación nuevamente, después de un tiempo en la llamada de servicio temporal stopForgroundService (verdadero) para descartar la ontificación en curso.fuente
También puede declarar su aplicación como persistente.
<application android:icon="@drawable/icon" android:label="@string/app_name" android:theme="@style/Theme" *android:persistent="true"* > </application>
Básicamente, esto establece su aplicación en una prioridad de memoria más alta, disminuyendo la probabilidad de que sea eliminada.
fuente
Desarrollé un reproductor multimedia simple hace un par de meses. Entonces, lo que creo es si estás haciendo algo como:
Intent i = new Intent(this, someServiceclass.class);
startService (i);
Entonces, el sistema no debería poder matar su servicio.
referencia : lea el párrafo que discute cuándo el sistema detiene el servicio
fuente