フォアグラウンド サービス

フォアグラウンド サービスは、ユーザーが認識できるオペレーションを実行します。

フォアグラウンド サービスではステータスバーの通知を表示して、アプリがフォアグラウンドでタスクを実行していることと、システム リソースを消費していることをユーザーに知らせます。

フォアグラウンド サービスを使用するアプリの例としては、次のようなものが挙げられます。

  • フォアグラウンド サービスで音楽を再生する音楽プレーヤー アプリ。通知として、現在再生中の曲が表示されることがあります。
  • ユーザーから権限を取得した後に、フォアグラウンド サービスでのユーザーのランニングを記録するフィットネス アプリ。この通知には、現在のフィットネス セッション中にユーザーが移動した距離が表示されることがあります。

フォアグラウンド サービスは、ユーザーがアプリを直接操作していないときでも、ユーザーが認識できるタスクをアプリが実行する必要がある場合にのみ使用します。アクションの重要度が低く、優先度が最も低い通知を使用する場合は、代わりにバックグラウンド タスクを作成します。

このドキュメントでは、フォアグラウンド サービスの使用に必要な権限と、フォアグラウンド サービスを開始してバックグラウンドから削除する方法について説明します。また、特定のユースケースをフォアグラウンド サービスのタイプに関連付ける方法と、バックグラウンドで実行されているアプリからフォアグラウンド サービスを開始したときに適用されるアクセス制限についても説明します。

ユーザーがデフォルトで通知を閉じることができる

Android 13(API レベル 33)以降では、ユーザーはフォアグラウンド サービスに関連付けられた通知をデフォルトで閉じることができます。これを行うには、ユーザーが通知をスワイプします。従来は、フォアグラウンド サービスが停止またはフォアグラウンドから削除されない限り、通知が閉じられることはありません。

ユーザーが通知を非表示にできないようにするには、Notification.Builder を使用して通知を作成するときに、truesetOngoing() メソッドに渡します。

通知をすぐに表示するサービス

フォアグラウンド サービスが次のいずれかの特性を持つ場合、Android 12 以降を搭載したデバイスであっても、サービスの開始直後に関連する通知が表示されます。

Android 13(API レベル 33)以降では、ユーザーが通知権限を拒否しても、フォアグラウンド サービスに関連する通知はタスク マネージャーに表示されますが、通知ドロワーには表示されません。

マニフェストでフォアグラウンド サービスを宣言する

アプリのマニフェストで、<service> 要素を使用してアプリの各フォアグラウンド サービスを宣言します。サービスごとに、android:foregroundServiceType 属性を使用して、サービスが実行する処理の種類を宣言します。

たとえば、アプリが音楽を再生するフォアグラウンド サービスを作成する場合、そのサービスを次のように宣言できます。

<manifest xmlns:android="http://schemas.android.com/apk/res/android" ...>
  <application ...>

    <service
        android:name=".MyMediaPlaybackService"
        android:foregroundServiceType="mediaPlayback"
        android:exported="false">
    </service>
  </application>
</manifest>

サービスに複数のタイプが適用される場合は、| 演算子で区切ってください。たとえば、カメラとマイクを使用するサービスは、次のように宣言します。

android:foregroundServiceType="camera|microphone"

フォアグラウンド サービスの権限をリクエストする

Android 9(API レベル 28)以降をターゲットとし、フォアグラウンド サービスを使用するアプリは、次のコード スニペットに示すように、アプリ マニフェストで FOREGROUND_SERVICE をリクエストする必要があります。これは標準の権限であるため、リクエスト元のアプリに自動的に付与されます。

また、API レベル 34 以降をターゲットとしているアプリは、フォアグラウンド サービスが実行する処理の種類に応じた適切な権限タイプをリクエストする必要があります。それぞれのフォアグラウンド サービス タイプには、対応する権限タイプがあります。たとえば、アプリがカメラを使用するフォアグラウンド サービスを起動する場合は、FOREGROUND_SERVICE 権限と FOREGROUND_SERVICE_CAMERA 権限の両方をリクエストする必要があります。これらはすべて通常の権限であるため、マニフェストにリストされている場合、システムによって自動的に付与されます。

<manifest xmlns:android="http://schemas.android.com/apk/res/android" ...>

    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA"/>

    <application ...>
        ...
    </application>
</manifest>

フォアグラウンド サービスの前提条件

Android 14(API レベル 34)以降では、フォアグラウンド サービスを起動すると、サービスタイプに基づいて特定の前提条件がシステムによってチェックされます。たとえば、location タイプのフォアグラウンド サービスを起動しようとすると、システムはアプリに ACCESS_COARSE_LOCATION 権限または ACCESS_FINE_LOCATION 権限のいずれかがすでにあることを確認します。一致していない場合、システムは SecurityException をスローします。

このため、フォアグラウンド サービスを開始する前に、必要な前提条件を満たしていることを確認する必要があります。フォアグラウンド サービス タイプのドキュメントでは、各フォアグラウンド サービス タイプに必要な前提条件が記載されています。

フォアグラウンド サービスを開始する

サービスをフォアグラウンド サービスとして実行するようシステムにリクエストする前に、サービス自体を開始します。

Kotlin

val intent = Intent(...) // Build the intent for the service
context.startForegroundService(intent)

Java

Context context = getApplicationContext();
Intent intent = new Intent(...); // Build the intent for the service
context.startForegroundService(intent);

サービス内(通常は onStartCommand())で、サービスをフォアグラウンドで実行するようリクエストできます。そのためには、ServiceCompat.startForeground() を呼び出します(androidx-core 1.12 以降で利用可能)。このメソッドは、次のパラメータを受け取ります。

これらのタイプは、特定のユースケースによっては、マニフェストで宣言されているタイプのサブセットになる場合があります。さらにサービスタイプを追加する必要がある場合は、startForeground() を再度呼び出します。

たとえば、フィットネス アプリがランニング トラッカー サービスを実行しているとします。このサービスでは、常に location 情報が必要ですが、メディアを再生する必要はありません。マニフェストで locationmediaPlayback の両方を宣言する必要があります。ランニングを開始したユーザーが位置情報の記録のみを行いたい場合は、startForeground() を呼び出して ACCESS_FINE_LOCATION 権限のみを渡す必要があります。次に、ユーザーが音声の再生を開始する場合は、startForeground() を再度呼び出し、すべてのフォアグラウンド サービス タイプのビット単位の組み合わせ(この場合は ACCESS_FINE_LOCATION|FOREGROUND_SERVICE_MEDIA_PLAYBACK)を渡します。

以下に、カメラのフォアグラウンド サービスを起動する例を示します。

Kotlin

class MyCameraService: Service() {

  private fun startForeground() {
    // Before starting the service as foreground check that the app has the
    // appropriate runtime permissions. In this case, verify that the user has
    // granted the CAMERA permission.
    val cameraPermission =
            PermissionChecker.checkSelfPermission(this, Manifest.permission.CAMERA)
    if (cameraPermission != PermissionChecker.PERMISSION_GRANTED) {
        // Without camera permissions the service cannot run in the foreground
        // Consider informing user or updating your app UI if visible.
        stopSelf()
        return
    }

    try {
        val notification = NotificationCompat.Builder(this, "CHANNEL_ID")
            // Create the notification to display while the service is running
            .build()
        ServiceCompat.startForeground(
            /* service = */ this,
            /* id = */ 100, // Cannot be 0
            /* notification = */ notification,
            /* foregroundServiceType = */
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA
            } else {
                0
            },
        )
    } catch (e: Exception) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
                && e is ForegroundServiceStartNotAllowedException) {
            // App not in a valid state to start foreground service
            // (e.g. started from bg)
        }
        // ...
    }
  }
}

Java

public class MyCameraService extends Service {

    private void startForeground() {
        // Before starting the service as foreground check that the app has the
        // appropriate runtime permissions. In this case, verify that the user
        // has granted the CAMERA permission.
        int cameraPermission =
            ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
        if (cameraPermission == PackageManager.PERMISSION_DENIED) {
            // Without camera permissions the service cannot run in the
            // foreground. Consider informing user or updating your app UI if
            // visible.
            stopSelf();
            return;
        }

        try {
            Notification notification =
                new NotificationCompat.Builder(this, "CHANNEL_ID")
                    // Create the notification to display while the service
                    // is running
                    .build();
            int type = 0;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                type = ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA;
            }
            ServiceCompat.startForeground(
                    /* service = */ this,
                    /* id = */ 100, // Cannot be 0
                    /* notification = */ notification,
                    /* foregroundServiceType = */ type
            );
        } catch (Exception e) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S &&
                    e instanceof ForegroundServiceStartNotAllowedException
            ) {
                // App not in a valid state to start foreground service
                // (e.g started from bg)
            }
            // ...
        }
    }

    //...
}

フォアグラウンドからサービスを削除する

サービスをフォアグラウンドから削除するには、stopForeground() を呼び出します。このメソッドは、ステータスバーの通知も削除するかどうかを示すブール値を受け取ります。サービスは引き続き実行されます。

フォアグラウンドで実行中のサービスを停止すると、通知は削除されます。

フォアグラウンド サービスを実行しているアプリをユーザーが自発的に停止した場合の処理

通知ドロワーの下部には、現在バックグラウンドで実行されているアプリの数を示すボタンがあります。このボタンを押すと、ダイアログが開き、さまざまなアプリの名前がリストされます。[停止] ボタンは各アプリの右側にあります。
図 1. Android 13 以降を搭載したデバイスでのタスク マネージャーのワークフロー。

Android 13(API レベル 33)以降では、アプリのターゲット SDK バージョンに関係なく、ユーザーは通知ドロワーからワークフローを完了して、フォアグラウンド サービスが進行中のアプリを停止できます。タスク マネージャーと呼ばれるこのアフォーダンスには、現在フォアグラウンド サービスを実行しているアプリのリストが表示されます。

このリストには、[有効なアプリ] というラベルが付きます。各アプリの横には [停止] ボタンがあります。図 1 は、Android 13 を搭載したデバイスでのタスク マネージャーのワークフローを示しています。

タスク マネージャーで、アプリの隣にある [Stop] ボタンをユーザーが押すと、次のアクションが実行されます。

  • アプリがメモリから削除されます。そのため、実行中のフォアグラウンド サービスだけでなく、アプリ全体が停止します。
  • システムがアプリのアクティビティのバックスタックを削除します。
  • メディアの再生が停止します。
  • フォアグラウンド サービスに関連付けられた通知は削除されます。
  • アプリは履歴に残ります。
  • スケジュールされたジョブは、スケジュールされた時刻に実行されます。
  • アラームは、設定した時刻または時間枠に鳴ります。

ユーザーがアプリを停止している間と停止した後にアプリが期待どおりに動作することをテストするには、ターミナル ウィンドウで次の ADB コマンドを実行します。

adb shell cmd activity stop-app PACKAGE_NAME

除外

特定のタイプのアプリには、以下のセクションで説明するいくつかのレベルの除外が適用されます。

除外は、プロセス単位ではなくアプリ単位で適用されます。アプリ内の 1 つのプロセスが除外されると、そのアプリ内の他のプロセスもすべて除外されます。

タスク マネージャーにまったく表示されないようにする

次のアプリはフォアグラウンド サービスを実行できますが、タスク マネージャーにはまったく表示されません。

  • システムレベルのアプリ
  • 緊急情報サービスアプリ(つまり、ROLE_EMERGENCY ロールを持つアプリ)
  • デモモードのデバイス

ユーザーによる停止対象からの除外

次のタイプのアプリがフォアグラウンド サービスを実行すると、タスク マネージャーに表示されますが、アプリ名の横にユーザーがタップできる [停止] ボタンが表示されません。

フォアグラウンド サービスの代わりに専用 API を使用する

多くのユースケースでは、フォアグラウンド サービスで行う作業に使用できるプラットフォーム API や Jetpack API があります。適切な専用 API がある場合は、ほとんどの場合、フォアグラウンド サービスではなく、その API を使用する必要があります。多くの場合、専用 API は、独自に構築する必要があるユースケース固有の追加機能を提供します。たとえば、 Bubbles API は、チャットバブル機能を実装する必要があるメッセージ アプリの複雑な UI ロジックを処理します。

フォアグラウンド サービスのタイプに関するドキュメントには、フォアグラウンド サービスの代わりに使用できる優れた代替手段がリストされています。

バックグラウンドからのフォアグラウンド サービスの起動に関する制限

Android 12 以降をターゲットとするアプリでは、アプリがバックグラウンドで実行されている間は、いくつかの特殊なケースを除いて、フォアグラウンド サービスを開始できません。アプリがバックグラウンドで実行されているときにフォアグラウンド サービスを起動しようとしたときに、フォアグラウンド サービスが例外ケースのいずれかを満たさない場合、システムは ForegroundServiceStartNotAllowedException をスローします。

また、アプリが使用中の権限(ボディセンサー、カメラ、マイク、位置情報の権限)を必要とするフォアグラウンド サービスを起動する必要がある場合、アプリがバックグラウンド起動の制限の免除のいずれかに該当する場合でも、アプリがバックグラウンドで実行されている間はサービスを作成できません。その理由については、使用中の権限が必要なフォアグラウンド サービスの起動に関する制限をご覧ください。

バックグラウンド開始制限の除外

次の状況では、アプリがバックグラウンドで実行されている場合でも、フォアグラウンド サービスを開始できます。

使用中の権限が必要なフォアグラウンド サービスの起動に関する制限

Android 14(API レベル 34)以降では、使用中の権限が必要なフォアグラウンド サービスを開始する場合に、注意すべき特別な状況があります。

Android 14 以降をターゲットとするアプリの場合、フォアグラウンド サービスの作成時にオペレーティング システムがチェックを行い、そのサービスタイプに適したすべての権限がアプリに付与されていることを確認します。たとえば、microphone タイプのフォアグラウンド サービスを作成すると、オペレーティング システムはアプリに現在 RECORD_AUDIO 権限があることを確認します。その権限がない場合、システムは SecurityException をスローします。

使用中の権限では、問題が発生する可能性があります。アプリに使用中の権限がある場合、その権限がフォアグラウンドにある間のみ付与されます。つまり、アプリがバックグラウンドにあり、カメラ、位置情報、またはマイクタイプのフォアグラウンド サービスを作成しようとすると、システムはアプリに現在必要な権限が付与されていないと認識し、SecurityException をスローします。

同様に、アプリがバックグラウンドにあり、BODY_SENSORS_BACKGROUND 権限を必要とするヘルスサービスを作成する場合、アプリには現在その権限がないため、システムは例外をスローします。(これは、ACTIVITY_RECOGNITION のような異なる権限を必要とするヘルスサービスの場合は適用されません)。PermissionChecker.checkSelfPermission() を呼び出しても、この問題は防止されません。アプリに使用中の権限がある場合、アプリがその権限を持っているかどうかを確認するために checkSelfPermission() を呼び出した場合、アプリがバックグラウンドにあっても PERMISSION_GRANTED が返されます。このメソッドが PERMISSION_GRANTED を返すと、「アプリが使用中の間、アプリにこの権限がある」ということを意味します。

このため、フォアグラウンド サービスが使用中の権限を必要とする場合は、アプリが定義された除外のいずれかに該当する場合を除き、アプリが可視アクティビティを行っている間に Context.startForegroundService() または Context.bindService() を呼び出す必要があります。

使用中権限の制限の免除

状況によっては、アプリが バックグラウンドで実行されているときにフォアグラウンド サービスが開始しても、アプリがフォアグラウンドで実行されている(「使用中」に)位置情報、カメラ、マイクの情報にアクセスできる場合があります。

同様の状況で、サービスが locationフォアグラウンド サービス タイプを宣言し、ACCESS_BACKGROUND_LOCATION 権限を持つアプリによって開始された場合、このサービスは、アプリがバックグラウンドで実行されている場合でも、常に位置情報にアクセスできます。

以下に、これらの状況を示します。

  • システム コンポーネントがサービスを開始します。
  • このサービスはまず、アプリ ウィジェットを操作します。
  • このサービスはまず、通知を操作します。
  • このサービスは、別の可視アプリから送信された PendingIntent として開始されます。
  • このサービスは、デバイス所有者モードで実行される Device Policy Controller であるアプリによって開始されます。
  • このサービスは、VoiceInteractionService を提供するアプリによって開始されます。
  • このサービスは、START_ACTIVITIES_FROM_BACKGROUND 特権を持つアプリによって開始されます。
アプリで影響を受けるサービスを特定する

アプリをテストするとき、フォアグラウンド サービスを開始します。開始されたサービスが、位置情報、マイク、カメラに対するアクセスを制限されている場合は、次のメッセージが Logcat に表示されます。

Foreground service started from background can not have \
location/camera/microphone access: service SERVICE_NAME