通知を表示せずにForeground()を開始するにはどうすればよいですか?


90

サービスを作成してフォアグラウンドで実行したいと思います。

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

いくつか例を挙げていただけますか?代替手段はありますか?

私のアプリサービスはメディアプレーヤーをやっています。アプリがサービス自体を強制終了する以外に、システムがサービスを強制終了しないようにする方法(ボタンで音楽を一時停止または停止するなど)。


11
通知なしに「フォアグラウンド」サービスを利用することはできません。限目。
Jug6ernaut 2012年

1
「偽の」通知を出すのはどうですか?それはトリックですか?
ムハンマドレスナリズキプラタマ2012

フォアグラウンド通知が設定されたら、Rubberアプリを使用して「バックグラウンド通知で実行中」を削除できます。
ローラン

1
@MuhammadResnaRizkiPratama、受け入れられた回答を変更することを検討しますか?この質問は非常に人気がありますが、受け入れられた回答は完全に古く、手間がかかりすぎており、開発者がこれを必要とする理由を推測しています。信頼性が高く、OSのバグを悪用せず、ほとんどのAndroidデバイスで動作するため、この回答をお勧めします。
サム

回答:


95

Androidプラットフォームのセキュリティ機能として、あなたがすることはできません、下のいずれかの状況、また通知をせずに前景化サービスを提供しています。これは、フォアグラウンドサービスが大量のリソースを消費し、バックグラウンドサービスとは異なるスケジューリング制約(つまり、すぐに強制終了されない)の影響を受け、ユーザーはバッテリーを消費している可能性があるものを知る必要があるためです。だから、これをしないでください。

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


3
ありがとう。これにより、setForegroundが通知を必要とする理由が明確になります。
ムハンマドレスナリズキプラタマ2012

21
さて、あなたにはそれをする理由があるようです、ユーザーはそれを求めました。おっしゃるように不誠実かもしれませんが、私が取り組んでいる製品をテストグループから依頼されました。たぶんAndroidには、常に実行されていることがわかっている一部のサービスからの通知を非表示にするオプションが必要です。それ以外の場合、通知バーはクリスマスツリーのように見えます。
ラドゥ2013年

3
@Raduは実際には、フォアグラウンドにそれほど多くのアプリを配置するべきではありません。スケジュールが異なるため(基本的に、アプリが停止しないため)、バッテリーの寿命が短くなります。これはmodには受け入れられるかもしれませんが、そのオプションがすぐにバニラAndroidになるとは思いません。「ユーザー」は、通常、彼らのために最善だかわからない...
のKristopher Micinski

2
@Raduはあなたの議論をサポートしていません。「受賞歴のあるアプリ」は通常、システムの不整合(タスクキラーなど)を通じてAndroidの穴を実際に「修正」するアプリです。「受賞歴のあるアプリ」が使用するという理由だけでフォアグラウンドサービスを使用する必要がある理由はありません。使用する場合は、ユーザーのバッテリーを殺すことを認めています。
クリストファーミシンスキー2013年

2
どうやら、この方法は4.3以降は機能しなくなります。plus.google.com/u/0/105051985738280261832/posts/MTinJWdNL8t
erbi 2013

79

更新:これはAndroid7.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))。

Voilà!通知はまったくなく、2番目のサービスは実行を続けます。


23
これをありがとう。一部の人々は、社内で使用するためにAndroidの開発が行われていることに気付いていないと思います(つまり、市場に出たり、Joe Blowに販売したりすることを意図したものではありません)。「サービス通知の表示をやめる」などと言われることもあり、一般消費者向けのコーシャでなくても回避策を見るのは良いことです。
jamieB 2013

5
@JamieBこれ以上同意できませんでした...私はDianneHackbornに、バックグラウンドサービスの概念全体を再考し、通知なしでバックグラウンドでサービスを実行する許可を追加する必要があることを提案しました。通知があるかどうかは開発者にとって重要ではありません-それを削除するのはUSERリクエストです!:)ちなみに、それがあなたにも機能することを確認できますか?
Lior Iluz 2013

1
@JamieB user875707は、通知のIDではなくアイコンパラメータ(アイコンのリソースID)を0に設定するように指示しています(その場合、ドキュメントに「startForeground」は機能しないと記載されています)。
wangqi060934 2013

9
もちろん、これはプラットフォームの将来のバージョンでは機能しないと想定する必要があります。
hackbod 2014

1
@JamieBこれをAndroid5.0.1で実際にテストしましたが、それでも機能します。
Lior Iluz 2015年

20

これはAndroid7.1以降では機能しなくなり、GooglePlayのデベロッパーポリシーに違反する可能性があります

代わりに、ユーザーにサービス通知をブロックしてもらいます。


これが、LiorIluzによる回答のテクニックの私の実装です。

コード

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
  • ソニーXperiaM
    • 4.1.2
    • 4.3
  • サムスンのギャラクシー ?
    • 4.4.2
    • 5.X
  • Genymotion
    • 5.0
    • 6.0
  • CyanogenMod
    • 5.1.1

Android7.1以降は機能しなくなりました。


2
まだテストしていませんが、少なくともその許可があればいいのですが!!! 「ToGoogle」の部分の+1、私のユーザーはアプリをバックグラウンドで実行し続けるために必要な通知について不平を言っています、私はスカイプ/ラマや他のアプリに必要な通知についても不平を言っています
Rami Dabain 2016

この例を使用してアラームをリッスンする方法については申し訳ありません。私はalarmManagerでアラームを設定するアプリを開発していますが、アプリを閉じると(最近のアプリ->クリア)すべてのアラームも削除され、これを防ぐ方法を見つけるためにトレーニングを行っています
Ares91 2017

@ Ares91、そのために別のStackOverflow質問を作成してみてください。また、関連するコードを含め、できるだけ多くの情報を含めるようにしてください。アラームについてはよくわかりませんが、この質問はサービスに関するものです。
サム

@Samどちらのサービスを最初に呼び出す必要があるか、ForegroundEnablingServiceまたはForground
Kamran Majeed

@AndroidManForegroundService
サム

14

あなたはこれを使うことができます(@KristopherMicinskiによって提案されたように):

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

更新:

これは、Android KitKat +リリースでは許可されなくなったことに注意してください。また、@ Kristopher Micinskiが述べたように、これはAndroidの設計原則に多かれ少なかれ違反しており、バックグラウンド操作がユーザーに表示されることに注意してください。


2
この通知に渡された描画可能が0の場合、サービスがフォアグラウンドに行くことはありませんSDK 17でもう受け入れられるようには見えませんのでご注意
Snicolas

これはバグであり、うまくいけば修正されました。フォアグラウンドサービスの考え方は、殺される可能性が低いということです。これは、ユーザーがその存在を認識できるようにする方法です。
Martin Marconcini 2013年

4
人造人間18号では、通知は表示されなくなりましたが、「アプリが実行中です。タッチして詳細を確認するか、アプリを停止してください」と表示されます
Emanuel Moecklin 2013

1
私の顧客の1人からのスクリーンショット:1gravity.com/k10/Screenshot_2013-07-25-12-35-49.jpg。私も4.3デバイスを持っており、その結果を確認できます。
Emanuel Moecklin 2013

2
警告:Android 4.1.2(SDK 16)を搭載したSony Ericsson LT26i(Xperia S)からクラッシュレポートを受け取ります:android.app.RemoteServiceException:パッケージから不正な通知が投稿されました...:アイコンを作成できませんでした:StatusBarIcon(pkg = ... id = 0x7f020052 level = 0visible = true num = 0)SDK17までアイコンIDを0に設定しました。SDK 18から、有効なドローアブルリソースに設定しました。たぶん、SDK 16の有効なアイコンIDが必要です!
almisoft 2013

13

警告:この回答は機能しているように見えますが、実際には、サービスがフォアグラウンドサービスになるのを黙って妨げています

元の答え:


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

編集

Pre-HoneycombおよびAndroid4.4以降で動作させるNotificationCompat.Builderには、の代わりにSupport Libraryv7が提供するものを使用してくださいNotification.Builder


1
これは、4.3(18)@vladsolで完全に機能します。なぜこの答えにまだ他の賛成票がないのだろうか?
Rob McFeely 2015

1
Android N Preview 4でこれを試しましたが、機能しませんでした。Notification.BuilderSupport Libraryv4NotificationCompat.BuilderとSupportLibraryv7を試してみましたNotificationCompat.Builder。通知ドロワーまたはステータスバーに通知が表示されませんでしたが、とを使用getRunningServices()して確認したところ、サービスがフォアグラウンドモードで実行されていませんでしたdumpsys
サム

@Sam、このバグは以前のバージョンでは表示されませんよね?
Anggrayudi H 2016

@AnggrayudiH、「このバグ」とは、通知が表示されないことを意味しますか?それとも、サービスがフォアグラウンドモードにならないということですか?
サム

1
これは私にはうまくいきません。id!= 0が送信されるとプロセスはフォアグラウンドとして開始されますが、id = 0の場合はフォアグラウンドとして開始されません。adb shell dumpsys activity services確認に使用します。
beetree 2016年

10

あなたは上の通知非表示にすることができますアンドロイド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でテスト済み。このソリューションは、Android8以下では機能しません。


1
良い回避策。また、Android 10ではアイコンが必要だと思います。アイコンに透明なプレースホルダー画像を使用すると、問題が解決します。
shyos

7

更新:これはAndroid4.3以降では機能しなくなりました


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

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

3
Android N Preview 4では、これは機能しません。(YourServiceName) is runningアイコンを指定しない場合、Androidは独自の通知ではなく通知を表示します。CommonsWareによると、これは、Android 4.3以降の場合されています:commonsware.com/blog/2013/07/30/...
サム・

1
今日、いくつかのテストを行い、これがAndroid4.3以降では機能しないことを確認しました。
サム

5

更新:これはAndroid4.3以降では機能しなくなりました


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

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


9
コマンド「adbshel​​ldumpsys activity services」を使用して、「isForeground」がtrueに設定されているかどうかを確認します。

1
または、空のNotification()コンストラクターを呼び出すだけです。
johsin18 2012

これは私のために働いた。初めてサービスを夜間に実行したので、間違いなくフォアグラウンドにあり(さらに、dumpsysによると)、通知はありません。
jamieB 2013

これはAndroid4.3(API 18)では機能しなくなったことに注意してください。OSは、プレースホルダー通知を通知ドロワーに配置します。
サム

4

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

ここでのほとんどの回答は、機能しないか、フォアグラウンドサービスを中断するか、GooglePlayポリシーに違反しています

通知を確実かつ安全に非表示にする唯一の方法は、ユーザーに通知をブロックさせることです。

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.0-8.1

OSは通知を「バックグラウンドで実行中」または「バッテリー使用中」の通知に置き換えるだけなので、AndroidOで通知をブロックする価値はありません。

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

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

この答えはおそらく正しくて便利ですが、問題の解決にどのように役立つかを説明するために、いくつかの説明を一緒に含めることをお勧めします。これは、機能を停止する原因となる変更(おそらく無関係)があり、ユーザーがかつてどのように機能したかを理解する必要がある場合に、将来特に役立ちます。
ケビンブラウン

Android4.3は実際にはAPI18だと思います。また、このメソッドはステータスバーからアイコンを非表示にするだけです。アイコンはまだ通知に存在します。
サム

通知からアイコンを非表示にするには、空の画像を追加できますmBuilder.setSmallIcon(R.drawable.blank);
vlad sol 2015

1
キットカットのソースを調べていますが、ゼロID方式は機能しないようです。IDがゼロの場合、サービスレコードはフォアグラウンドではないように更新されます。
Jeffrey Blattman 2015年

2

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


1
Android 8.1の場合:「startForegroundの不正な通知:java.lang.RuntimeException:サービス通知の無効なチャネル」
T-

個人的には、apps are running in the background通知はアプリ固有の通知よりもさらに悪いと思うので、このアプローチが価値があるかどうかはわかりません。
サム

-2

更新:これはAndroid7.1以降では機能なくなりました


アプリのoom_adjを1にする方法は次のとおりです(ANDROID 6.0 SDKエミュレーターでテスト済み)。一時的なサービスを追加しますstartForgroundService(NOTIFICATION_ID, notificion)。メインのサービスコールで。次にstartForgroundService(NOTIFICATION_ID, notificion)、同じ通知IDで一時サービス呼び出しを再開します。しばらくすると、一時サービス呼び出しstopForgroundService(true)を実行して、オンになっているオンティフィケーションを閉じます。


これは私が知っている唯一の実用的な解決策です。しかし、それはすでに別の答えでカバーされています
サム

-3

アプリケーションを永続として宣言することもできます。

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

これにより、基本的にアプリのメモリ優先度が高くなり、アプリが強制終了される可能性が低くなります。


5
これは間違っています。永続化できるのはシステムアプリのみです:groups.google.com/forum/?fromgroups
#!topic

-6

私は数ヶ月前にシンプルなメディアプレーヤーを開発しました。だから私が信じているのは、あなたが次のようなことをしている場合です:

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

startService(i);

そうすれば、システムはあなたのサービスを殺すことができないはずです。

参照システムがいつサービスを停止するかについて説明している段落を読んでください


私はいくつかの記事を読みました。startService()を実行するだけの場合、システムはより多くのメモリを必要とします。したがって、システムはそのサービスを強制終了します。それは本当ですか?実験を行う時間がありません。
ムハンマドレスナリズキプラタマ2012

1
ムハンマド、それは本当です-startForeground()の目的は、サービスがより長く存続できるように、バックグラウンドサービスよりも高い「メモリ優先度」をサービスに効果的に与えることです。startForeground()は通知を使用して、実行中のより永続的で殺しにくいサービスをユーザーが認識できるようにする必要があります。
dustinB 2012

これは単に真実ではありません。Androidで殺せないサービスを作ることは事実上不可能です。Androidは、フォアグラウンド以外のサービスを簡単に強制終了して、メモリを解放します。
サム
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.