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

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

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

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

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

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

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

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

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

    <service
        android:name=".MyMediaPlaybackService"
        android:foregroundServiceType="mediaPlayback"
        android:exported="false">
    </service>
</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 =
            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 {
        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 を搭載したデバイスでのタスク マネージャーのワークフローを示しています。

ユーザーがタスク マネージャーでアプリの横にある [停止] ボタンを押すと、以下のアクションが行われます。

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

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

adb shell cmd activity stop-app PACKAGE_NAME

除外

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

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

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

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

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

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

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

フォアグラウンド サービスではなく専用 API を使用する

多くのユースケースでは、フォアグラウンド サービスの処理に使用できるプラットフォーム API や Jetpack 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 など、異なる権限を必要とするヘルスサービスの場合は適用されません)。ContextCompat.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