前景服務

前景服務執行的是使用者察覺的作業。

前景服務會顯示狀態列 通知,提醒使用者 應用程式正在前景執行工作並消耗系統資源。

以下列舉使用前景服務的應用程式:

  • 音樂播放器應用程式在前景服務中播放音樂,通知 可能會顯示目前播放的歌曲
  • 當使用者在前景服務中記錄跑步的健身應用程式,之後 徵得使用者的許可通知可能會顯示距離 使用者在目前的健身工作階段中所走過的距離。

只在應用程式需要執行工作時,才使用前景服務 但就算使用者並未直接與 互動 應用程式如果動作的重要性太低,您想要使用 建立背景為「最低優先順序」的通知 工作

本文件說明瞭使用前景服務的必要權限。 以及如何啟動前景服務,以及如何從背景移除這類服務。此外, 說明如何將特定用途與前景服務類型建立關聯。 啟動前景服務後生效的存取權限制 從在背景執行的應用程式開始篩選

使用者預設能關閉通知

從 Android 13 (API 級別 33) 開始,使用者可以關閉通知 已與前景服務建立關聯使用者只要滑動螢幕即可 手勢。一般來說 除非前景服務停止或移除,否則不會關閉 從前景開始。

若您希望使用者不要關閉通知,請 true 加入setOngoing() 方法。Notification.Builder

立即顯示通知的服務

如果前景服務具備至少下列其中一項特性,則 系統會在服務啟動後立即顯示相關的通知 包括:

在 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_LOCATIONACCESS_FINE_LOCATION權限。否則,系統會擲回 SecurityException

因此,請務必確認您符合必要條件 啟動前景服務之前前景服務 type 說明文件 列出每種前景服務類型必備的必要條件。

啟動前景服務

如要要求系統以前景服務形式執行服務,請先啟動 服務本身:

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.

當使用者在 工作管理員,然後執行下列操作:

  • 系統會從記憶體中移除應用程式。因此,「整個應用程式」都會停止運作 而不只是執行中的前景服務
  • 系統會移除應用程式的活動返回堆疊。
  • 所有媒體播放作業都會停止,
  • 系統會移除與前景服務相關聯的通知。
  • 應用程式仍會留在記錄中。
  • 已排定的工作會在排定時間執行。
  • 鬧鐘會在排定的時間或時間範圍響起。
,瞭解如何調查及移除這項存取權。

在使用者停止應用程式期間和結束後,測試應用程式是否正常運作 應用程式,在終端機視窗中執行下列 ADB 指令:

adb shell cmd activity stop-app PACKAGE_NAME

豁免資格

系統會為特定類型的應用程式提供幾種豁免層級; 以下各節將說明。

豁免資格因應用程式而異,而非個別程序。如果系統在 應用程式中的所有其他程序也不受限制。

豁免於工作管理員

以下應用程式可執行前景服務,但不會顯示在 工作管理員:

使用者無法停止豁免

當下列類型的應用程式執行前景服務時,它們會顯示在 工作管理員,但任務管理員旁邊沒有「Stop」按鈕 使用者輕觸的應用程式名稱:

使用專為特定用途建立的 API,而非前景服務

在許多用途中,您可以透過平台或 Jetpack API 完成工作 也可以將前景服務用於這類用途如有需要 在大部分的情況下,您應一律使用這個 API 取代前景 課程中也會快速介紹 Memorystore 這是 Google Cloud 的全代管 Redis 服務專為特定用途設計的 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。 允許這項服務隨時存取位置資訊,即使 應用程式會在背景執行

下方清單列出下列情況:

判斷哪些服務會在應用程式中受到影響

在測試應用程式時,啟動其前景服務。如果已啟動的服務 已限制存取位置資訊、麥克風和相機,以下訊息 出現在 Logcat 中:

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