web-dev-qa-db-ja.com

通知を表示せずにstartForeground()を実行する方法は?

サービスを作成し、フォアグラウンドで実行するようにします。

ほとんどのサンプルコードには通知があります。しかし、通知を表示したくありません。それは可能ですか?

例を挙げてもらえますか?代替手段はありますか?

私のアプリサービスはmediaplayerを実行しています。 アプリがそれ自体を殺す以外にシステムが私のサービスを殺さないようにする方法(ボタンで音楽を一時停止または停止するように)。

Androidプラットフォームのセキュリティ機能として、cannotanyの状況では、通知もせずにフォアグラウンドサービスがあります。これは、フォアグラウンドサービスはバックグラウンドサービスと比べてより多くのリソースを消費し、異なるスケジューリングの制約を受ける(つまり、すぐに殺されない)ため、ユーザーはバッテリーを消費している可能性があるものを知る必要があるためです。 しないこれを行います。

ただし、それはis「偽の」通知を持つことが可能です。つまり、透明な通知アイコン(iirc)を作成できます。これはユーザーにとって非常に不誠実なものであり、バッテリーを破壊してマルウェアを作成する以外に、それを行う理由はありません。

82

更新:これは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)を呼び出します)。

ほら!通知はまったくなく、2番目のサービスは引き続き実行されます。

75
Lior Iluz

これはAndroid 7.1以降では機能せず、違反する可能性があります Google Playの開発者ポリシー

代わりに、 ユーザーにサービス通知をブロックさせる をお勧めします。


答え by Lior 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.0
    • 7.0
  • ソニーXperia M
    • 4.1.2
    • 4.3
  • サムスンのギャラクシー ?
    • 4.4.2
    • 5.X
  • Genymotion
    • 5.0
    • 6.0
  • CyanogenMod
    • 5.1.1

Android 7.1。以降は動作していません

19
Sam

これを使用できます(@Kristopher Micinskiが示唆するとおり):

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

更新:

これは、Android KitKat +リリースではもう許可されません。これは、バックグラウンドを作成するAndroid @Kristopher Micinskiが言及したユーザーに見える操作

15
Snicolas

通知の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システムによって破壊されることなく、高優先度で実行できることです。

[〜#〜] edit [〜#〜]

Pre-HoneycombおよびAndroid 4.4以降で動作するようにするには、NotificationCompat.Builderではなく、サポートライブラリv7が提供するNotification.Builderを使用してください。

9
Anggrayudi H

1つの回避策があります。アイコンを設定せずに通知を作成してみてください。通知は表示されません。それがどのように機能するのか分からないが、それは:)

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

Notificationのコンストラクターにiconパラメーターをゼロに設定し、結果の通知をstartForeground()に渡しました。ログにエラーも通知も表示されません。ただし、サービスが正常にフォアグラウンド化されたかどうかはわかりません。チェックする方法はありますか?

編集:dumpsysでチェックしました。実際、2.3システムではサービスがフォアグラウンドになっています。他のOSバージョンではまだ確認していません。

6
Alexander Pruss

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以下では動作しません

2
phnmnn

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アプリがバックグラウンドで実行されています'という通知が表示されます。

2
Pete

フォアグラウンドサービス通知をブロックする

Android 7.1以降を悪用して通知を隠すことはできません。代わりに、ユーザーにブロックさせます。

Android 4.1-7.1

唯一の方法は、アプリからのall通知をブロックすることです:

  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 Oの通知をブロックする価値はありません。OSは単に「バックグラウンドで実行中」または「バッテリー」通知。

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. ユーザーにチャンネルの通知をブロックさせる

2
Sam

バージョン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);
2
vlad sol