從應用程式啟動前景服務有兩個步驟。首先,您必須呼叫 context.startForegroundService() 啟動服務。接著,讓服務呼叫 ServiceCompat.startForeground(),將自身升級為前景服務。
必要條件
視應用程式指定的 API 級別而定,應用程式啟動前景服務的時間會受到一些限制。
如果應用程式指定 Android 12 (API 級別 31) 以上版本,則無法在背景執行時啟動前景服務,但有少數例外情況。如要進一步瞭解這項規則和例外狀況,請參閱「從背景啟動前景服務的限制」。
如果應用程式指定 Android 14 (API 級別 34) 以上版本為目標,則必須要求前景服務類型的適當權限。當應用程式嘗試將服務升級至前景時,系統會檢查是否有適當權限,如果應用程式缺少任何權限,就會擲回
SecurityException。舉例來說,如果您嘗試啟動location類型的前景服務,系統會檢查並確認應用程式是否已具備ACCESS_COARSE_LOCATION或ACCESS_FINE_LOCATION權限。前景服務類型說明文件列出了每種前景服務類型的必要條件。
推出服務
如要啟動前景服務,您必須先將其啟動為一般 (非前景) 服務:
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);
程式碼重點
- 程式碼片段會啟動服務。不過,服務尚未在前景執行。在服務本身中,您需要呼叫
ServiceCompat.startForeground(),將服務升級為前景服務。
將服務升級至前景
服務執行後,您需要呼叫 ServiceCompat.startForeground(),要求服務在前景執行。一般來說,您會在服務的 onStartCommand() 方法中呼叫這個方法。
ServiceCompat.startForeground() 採用下列參數:
- 服務。
- 正整數,可明確識別狀態列中的服務通知。
Notification物件本身。- 前景服務類型,用於識別服務執行的工作
您傳遞至 startForeground() 的前景服務類型,必須是資訊清單中宣告的類型,具體取決於特定用途。接著,如需新增更多服務類型,可以再次呼叫 startForeground()。
舉例來說,假設某個運動應用程式執行跑步追蹤服務,一律需要 location 資訊,但可能需要或不需要播放媒體。您必須在資訊清單中同時宣告 location 和 mediaPlayback。如果使用者開始跑步,且只想追蹤自己的位置,應用程式應呼叫 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) } // ... } } //... }
程式碼重點
- 應用程式已在資訊清單中宣告需要
CAMERA權限。不過,應用程式也必須在執行階段檢查,確保使用者已授予該權限。如果應用程式實際上沒有正確權限,應告知使用者這個問題。 - 不同版本的 Android 平台會推出不同的前景服務類型。這段程式碼會檢查執行的 Android 版本,並要求適當權限。
- 程式碼會檢查
ForegroundServiceStartNotAllowedException,以免在不允許的情況下嘗試啟動前景服務 (例如,在應用程式處於背景時,嘗試將服務升級至前景)。