如何startForeground()不显示通知?如何startForeground()不显示通知?

2019-05-17 13:09发布

我想创建一个服务,并使它在前台运行。

大多数例子代码有它的通知。 但我不希望出现任何通知。 那可能吗?

你能给我一些例子吗? 是否有其它方法吗?

我的应用程序服务是做媒体播放器。 如何使系统不杀我的服务,除了应用程序杀死它本身 (如暂停或按钮停止音乐)。

Answer 1:

由于Android平台的安全功能,你不能 ,在任何情况下,有前景化服务而不让一个通知。 这是因为前景化的服务消耗资源的重量,并受不同的调度限制(即,它不会因为迅速杀死),比后台服务,用户需要知道什么是可能吃他们的电池。 所以, 这样做。

但是,它可能有一个“假”的通知,也就是说,你可以做一个透明的通知图标(IIRC)。 这是极其虚伪到你的用户,你没有理由这样做,不是杀死他们的电池,从而创造恶意软件等。



Answer 2:

更新:这是在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);

我做了和平与事实通知本身仍然需要有但谁曾谁还要隐藏它,我可能已经找到了一个解决方法,以及:

  1. 开始用假服务startForeground()与通知和一切。
  2. 开始你要运行的真正的服务,还与startForeground()相同的通知ID)
  3. 停止第一个(假的)服务(你可以调用stopSelf()和调用的onDestroy stopForeground(true) )。

瞧! 根本没有通知和您的第二个服务继续运行。



Answer 3:

这不再是安卓7.1+工作。 这种技术可能会违反谷歌Play的开发者政策 ( Apps that introduce or exploit security vulnerabilities. )。

相反,我建议让用户阻止该服务的通知 。


下面是我的实现在技术,答案由利奥尔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;
    }

}

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" />

兼容性

测试和工作:

  • 官方模拟器
    • 4.0.2
    • 4.1.2
    • 4.2.2
    • 4.3.1
    • 4.4.2
    • 5.0.2
    • 5.1.1
    • 6
    • 7
  • 索尼的Xperia中号
    • 4.1.2
    • 4.3
  • 三星Galaxy ?
    • 4.4.2
    • 5.X
  • Genymotion
    • 5
    • 6
  • 的CyanogenMod
    • 5.1.1

不再担任的Android 7.1。



Answer 4:

你可以使用这个(由@Kristopher Micinski的建议):

Notification note = new Notification( 0, null, System.currentTimeMillis() );
note.flags |= Notification.FLAG_NO_CLEAR;
startForeground( 42, note );

更新:

请注意,这不是与Android奇巧+发布了允许的。 并牢记,这或多或少是违反在Android的设计原则,通过@Kristopher Micinski提到,让后台操作对用户可见



Answer 5:

只需设置您的通知的ID为零:

// 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系统的破坏,除非对高内存压力。

编辑

为了使其与前蜂窝和Android 4.4及更高版本工作,请确保您使用NotificationCompat.Builder代替它通过支持库V7提供, Notification.Builder



Answer 6:

的图标I参数给构造为通知设定为零,然后传递所产生的通知到startForeground()。 日志并没有通知,没有错误显示出来。 我不知道,不过,该服务是否成功前景化 - 有什么办法检查?

编辑:经过与dumpsys,堪与服务前景化我的2.3系统。 有没有与其他版本的操作系统还没有检查。



Answer 7:

有一个解决办法。 尽量不设置图标创建通知,通知不会显示。 不知道它是如何工作的,但它确实:)

    Notification notification = new NotificationCompat.Builder(this)
            .setContentTitle("Title")
            .setTicker("Title")
            .setContentText("App running")
            //.setSmallIcon(R.drawable.picture)
            .build();
    startForeground(101,  notification);


Answer 8:

版本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);


Answer 9:

我已经在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);

        }

    }

永久通知没有显示,但是你会看到Android的通知“X应用程序在后台运行”。



Answer 10:

块前台服务通知

安卓7.1+不能被利用来隐藏通知。 取而代之的是,让用户来阻止它。

搭载Android 4.1 - 7.1

唯一的办法就是阻止你的应用程序的所有通知:

  1. 发送用户的应用程序的详细信息屏幕:

     Uri uri = Uri.fromParts("package", getPackageName(), null); Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(uri); startActivity(intent); 
  2. 有用户模块应用的通知

请注意,这也会阻止你的应用程序的祝酒词。

Android的8

这不值得堵在Android澳通知,因为该操作系统将只是一个“ 在后台运行 ”或“ 使用电池 ”通知更换。

Android的9

使用通知信道阻塞只是服务通知。

  1. 指定服务通知通知信道
  2. 发送用户通知通道的设置

     Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS) .putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName()) .putExtra(Settings.EXTRA_CHANNEL_ID, myNotificationChannel.getId()); startActivity(intent); 
  3. 有用户块信道的通知



Answer 11:

您可以通过使用自定义布局与layout_height =“0dp”隐藏在Android 9通知

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>

上像素的1测试,机器人9.本解决方案并不在Android 8或更小的工作



Answer 12:

这里有一个方法,使您的应用程序的oom_adj 1(经测试,在ANDROID 6.0 SDK模拟器)。 添加一个临时服务,在你的主要服务调用startForgroundService(NOTIFICATION_ID, notificion) 然后启动临时服务呼叫startForgroundService(NOTIFICATION_ID, notificion)再次用相同的通知ID,在临时服务调用stopForgroundService(真)驳回onging ontification一段时间后。



Answer 13:

我开发了一个简单的媒体播放器,几个月前。 因此,我认为是,如果你正在做的事情,如:

Intent i = new Intent(this, someServiceclass.class);

startService(ⅰ);

然后,然后系统不应该是能杀你的服务。

参考 : 读其讨论时系统停止服务的段落



Answer 14:

您也可以声明你的应用程序为持续性。

<application
    android:icon="@drawable/icon"
    android:label="@string/app_name"
    android:theme="@style/Theme"
    *android:persistent="true"* >
</application>

这实质上是将您的应用程序在一个更高的内存优先级,降低它被杀死的概率。



文章来源: How to startForeground() without showing notification?