Saya ingin membuat layanan dan membuatnya berjalan di latar depan.
Sebagian besar kode contoh memiliki pemberitahuan di dalamnya. Tapi saya tidak ingin menampilkan pemberitahuan apa pun. Apakah itu mungkin?
Bisakah Anda memberi saya beberapa contoh? Apakah ada alternatif lain?
Layanan aplikasi saya sedang melakukan mediaplayer. Cara membuat sistem tidak mematikan layanan saya kecuali aplikasi mematikannya sendiri (seperti menjeda atau menghentikan musik dengan tombol).
android
android-service
foreground
Muhammad Resna Rizki Pratama
sumber
sumber
Jawaban:
Sebagai fitur keamanan platform Android, Anda tidak dapat , dalam keadaan apa pun , memiliki layanan latar depan tanpa pemberitahuan. Hal ini karena layanan latar depan menghabiskan lebih banyak sumber daya dan tunduk pada batasan penjadwalan yang berbeda (yaitu, tidak terbunuh dengan cepat) daripada layanan latar belakang, dan pengguna perlu mengetahui apa yang mungkin memakan baterai mereka. Jadi, jangan lakukan ini.
Namun, adalah mungkin untuk memiliki "palsu" pemberitahuan, yaitu, Anda dapat membuat ikon pemberitahuan transparan (iirc). Ini sangat tidak jujur bagi pengguna Anda, dan Anda tidak punya alasan untuk melakukannya, selain mematikan baterai mereka dan dengan demikian menciptakan malware.
sumber
Pembaruan: Ini telah "diperbaiki" di Android 7.1. https://code.google.com/p/android/issues/detail?id=213309
Sejak pembaruan 4.3, pada dasarnya tidak mungkin untuk memulai layanan
startForeground()
tanpa menunjukkan pemberitahuan.Namun, Anda dapat menyembunyikan ikon menggunakan API resmi ... tidak perlu ikon transparan: (Gunakan
NotificationCompat
untuk mendukung versi yang lebih lama)NotificationCompat.Builder builder = new NotificationCompat.Builder(context); builder.setPriority(Notification.PRIORITY_MIN);
Saya telah berdamai dengan kenyataan bahwa pemberitahuan itu sendiri masih perlu ada di sana, tetapi bagi siapa pun yang masih ingin menyembunyikannya, saya mungkin telah menemukan solusi untuk itu juga:
startForeground()
dengan notifikasi dan semuanya.startForeground()
(ID pemberitahuan yang sama)stopSelf()
dan dalam panggilan onDestroystopForeground(true)
).Voilà! Tidak ada pemberitahuan sama sekali dan layanan kedua Anda terus berjalan.
sumber
Ini tidak lagi berfungsi sejak Android 7.1 dan mungkin melanggar kebijakan pengembang Google Play .
Sebaliknya, minta pengguna memblokir notifikasi layanan .
Inilah implementasi saya dari teknik yang dijawab oleh Lior Iluz .
Kode
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" />
Kesesuaian
Diuji dan dikerjakan:
Tidak lagi berfungsi sejak Android 7.1.
sumber
ForegroundService
Anda dapat menggunakan ini (seperti yang disarankan oleh @Kopher Micki):
Notification note = new Notification( 0, null, System.currentTimeMillis() ); note.flags |= Notification.FLAG_NO_CLEAR; startForeground( 42, note );
MEMPERBARUI:
Harap dicatat bahwa ini tidak diperbolehkan lagi dengan rilis Android KitKat +. Dan perlu diingat bahwa ini kurang lebih melanggar prinsip desain di Android yang membuat operasi latar belakang terlihat oleh pengguna seperti yang disebutkan oleh @Kristopher Micinski
sumber
Peringatan : meskipun jawaban ini tampaknya berfungsi, sebenarnya jawaban tersebut secara diam-diam mencegah layanan Anda menjadi layanan latar depan .
Jawaban asli:
Cukup setel ID notifikasi Anda ke nol:
// 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); ...
Keuntungan yang didapat adalah, sebuah
Service
akan dapat berjalan dengan prioritas tinggi tanpa dihancurkan oleh sistem Android, kecuali pada tekanan memori tinggi.EDIT
Untuk membuatnya berfungsi dengan Pre-Honeycomb dan Android 4.4 dan lebih tinggi, pastikan Anda menggunakan
NotificationCompat.Builder
yang disediakan oleh Support Library v7, bukanNotification.Builder
.sumber
Notification.Builder
, Support Library v4NotificationCompat.Builder
dan Support Library v7NotificationCompat.Builder
. Notifikasi tidak muncul di panel samping notifikasi atau bilah status, tetapi layanan tidak berjalan dalam mode latar depan ketika saya memeriksanya menggunakangetRunningServices()
dandumpsys
.adb shell dumpsys activity services
untuk memverifikasi.Anda dapat menyembunyikan pemberitahuan di Android 9+ dengan menggunakan tata letak khusus dengan 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>
Diuji pada Pixel 1, android 9. Solusi ini tidak berfungsi di Android 8 atau kurang
sumber
Pembaruan: ini tidak lagi berfungsi di Android 4.3 dan di atasnya
Ada satu solusi. Coba buat notifikasi tanpa ikon pengaturan, dan notifikasi tidak akan muncul. Tidak tahu cara kerjanya, tapi memang :)
Notification notification = new NotificationCompat.Builder(this) .setContentTitle("Title") .setTicker("Title") .setContentText("App running") //.setSmallIcon(R.drawable.picture) .build(); startForeground(101, notification);
sumber
(YourServiceName) is running
pemberitahuan, bukan milik Anda sendiri, ketika Anda tidak menentukan ikon. Menurut CommonsWare, ini telah terjadi sejak Android 4.3: commonsware.com/blog/2013/07/30/…Pembaruan: ini tidak lagi berfungsi di Android 4.3 dan di atasnya
Saya menyetel parameter icon ke konstruktor untuk Notification ke nol, dan kemudian meneruskan notifikasi yang dihasilkan ke startForeground (). Tidak ada kesalahan dalam log dan tidak ada pemberitahuan yang muncul. Namun, saya tidak tahu apakah layanan berhasil di latar depan - adakah cara untuk memeriksanya?
Diedit: Diperiksa dengan dumpsys, dan memang layanan ini berada di latar depan pada sistem 2.3 saya. Belum memeriksa dengan versi OS lain.
sumber
Notification()
konstruktor kosong .Blokir notifikasi layanan latar depan
Sebagian besar jawaban di sini tidak berfungsi, merusak layanan latar depan , atau melanggar kebijakan Google Play .
Satu-satunya cara untuk menyembunyikan notifikasi dengan andal dan aman adalah meminta pengguna memblokirnya.
Android 4.1 - 7.1
Satu-satunya cara adalah memblokir semua notifikasi dari aplikasi Anda:
Arahkan pengguna ke layar detail aplikasi:
Uri uri = Uri.fromParts("package", getPackageName(), null); Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(uri); startActivity(intent);
Minta pengguna memblokir notifikasi aplikasi
Perhatikan bahwa ini juga memblokir toast aplikasi Anda.
Android 8.0 - 8.1
Tidak ada gunanya memblokir notifikasi di Android O karena OS hanya akan menggantinya dengan notifikasi " berjalan di latar belakang " atau " menggunakan baterai ".
Android 9+
Gunakan Saluran Pemberitahuan untuk memblokir pemberitahuan layanan tanpa mempengaruhi pemberitahuan Anda yang lain.
Arahkan pengguna ke pengaturan saluran notifikasi
Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS) .putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName()) .putExtra(Settings.EXTRA_CHANNEL_ID, myNotificationChannel.getId()); startActivity(intent);
Minta pengguna memblokir notifikasi saluran
sumber
versi 4.3 (18) dan di atasnya menyembunyikan pemberitahuan layanan tidak dimungkinkan, tetapi Anda dapat menonaktifkan ikon, versi 4.3 (18) dan di bawahnya dimungkinkan untuk menyembunyikan pemberitahuan
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);
sumber
Saya telah menemukan di Android 8.0 itu masih mungkin dengan tidak menggunakan saluran notifikasi.
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 { //... } } } }
Dan di 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); } }
Notifikasi terus-menerus tidak ditampilkan, namun Anda akan melihat notifikasi aplikasi Android 'x berjalan di latar belakang'.
sumber
apps are running in the background
notifikasi itu bahkan lebih buruk daripada notifikasi khusus aplikasi, jadi saya tidak yakin pendekatan ini sepadan.Pembaruan: ini tidak lagi berfungsi di Android 7.1 dan di atasnya
Berikut adalah cara untuk membuat oom_adj aplikasi Anda menjadi 1 (Diuji dalam emulator SDK ANDROID 6.0).Tambahkan layanan sementara, Di panggilan layanan utama Anda
startForgroundService(NOTIFICATION_ID, notificion)
. Kemudian mulai panggilan layanan sementarastartForgroundService(NOTIFICATION_ID, notificion)
dengan id notifikasi yang sama lagi, setelah beberapa saat dalam panggilan layanan sementara stopForgroundService (true) untuk menutup onging ontification.sumber
Anda juga bisa mendeklarasikan aplikasi Anda sebagai persistent.
<application android:icon="@drawable/icon" android:label="@string/app_name" android:theme="@style/Theme" *android:persistent="true"* > </application>
Ini pada dasarnya menetapkan aplikasi Anda pada prioritas memori yang lebih tinggi, sehingga mengurangi kemungkinan dimatikannya aplikasi.
sumber
Saya mengembangkan pemutar media sederhana beberapa bulan lalu. Jadi yang saya yakini adalah jika Anda melakukan sesuatu seperti:
Intent i = new Intent(this, someServiceclass.class);
startService (i);
Maka sistem seharusnya tidak dapat mematikan layanan Anda.
referensi : baca paragraf yang membahas kapan sistem menghentikan layanan
sumber