前台服务用于执行用户可察觉的操作。
前台服务显示状态栏 通知,让用户知道您的 应用正在前台执行任务并消耗系统资源。
使用前台服务的应用示例包括:
- 一款音乐播放器应用,用于在前台服务中播放音乐。通知 可能会显示当前正在播放的歌曲。
- 一款健身应用,可在前台服务中记录用户的跑步数据。 从用户处获取权限通知可能会显示距离 用户在当前健身课程中走过的距离。
仅在应用需要执行任务时使用前台服务 用户会注意到这一点,即使用户并非直接与 应用。如果此操作的重要性较低,以至于您想使用 最低优先级通知,创建背景 任务。
本文档介绍了使用前台服务所需的权限, 以及如何启动前台服务并将其从后台移除。它还 介绍了如何将某些用例与前台服务类型相关联,以及 启动前台服务时生效的访问限制 来自在后台运行的应用
用户可以默认关闭通知
从 Android 13(API 级别 33)开始,用户可以关闭通知 与前台服务相关联。为此,用户只需滑动一下手指 手势。传统上,通知 不会关闭,除非停止或移除前台服务 从前台运行
如果您希望用户不可关闭通知,请将以下代码传递
true
进入setOngoing()
方法,然后使用 Notification.Builder
创建通知。
立即显示通知的服务
如果某项前台服务至少具有以下特征之一,则 系统会在服务启动后立即显示相关通知, (即使是在搭载 Android 12 或更高版本的设备上):
- 该服务与包含操作按钮的通知相关联。
- 该服务具有
foregroundServiceType
共mediaPlayback
个,mediaProjection
或phoneCall
。 - 该服务根据通知的类别属性中的定义,提供与通话、导航或媒体播放相关的用例。
- 该服务通过在设置通知时将
FOREGROUND_SERVICE_IMMEDIATE
传入setForegroundServiceBehavior()
,已停用行为变更。
在 Android 13(API 级别 33)或更高版本中,如果用户拒绝 通知权限, 他们仍会在 任务管理器 但在抽屉式通知栏中看不到它们
在清单中声明前台服务
在应用清单中,声明应用的每个前台服务
(带有 <service>
)
元素。对于每项服务,请使用
android:foregroundServiceType
属性
来声明服务执行的工作类型。
例如,如果您的应用创建了一个用于播放音乐的前台服务,则 可能会按如下方式声明 Service:
<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
。
因此,您必须确认满足必要的前提条件 启动前台服务前。前台服务 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);
在该 Service 内(通常在 onStartCommand()
中),您可以请求
确保服务在前台运行为此,请调用
ServiceCompat.startForeground()
(在 androidx-core 1.12 及更高版本中提供)。此方法采用以下
参数:
- 服务
- 一个正整数,用于唯一标识状态栏中的通知
Notification
对象本身- 前台服务类型 识别服务完成的工作
这些类型可能是清单中声明的类型的子集,
具体取决于应用场景然后,如果您需要添加更多服务类型
您可以再次呼叫 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) } // ... } } //... }
从前台移除服务
要从前台移除服务,请调用
stopForeground()
。
此方法采用布尔值,指示是否移除状态栏
通知。请注意,服务会继续运行。
如果您在服务在前台运行时将其停止,其通知 已移除。
处理用户发起的停止运行前台服务的应用的行为
从 Android 13(API 级别 33)开始,用户可以从以下位置完成工作流: 抽屉式通知栏 停止具有持续前台服务的应用 目标 SDK 版本。这一功能称为 任务管理器,其中显示了 当前运行前台服务。
此列表的标签为使用中的应用。 每个应用旁边都有一个停止按钮。图 1 展示了 设备上运行的任务管理器工作流 Android 13。
当用户在界面中按应用旁边的 Stop 按钮时, 任务管理器,则会发生以下操作:
- 系统会从内存中移除您的应用。因此,您的整个应用都会停止, 而不仅仅是正在运行的前台服务
- 系统会移除应用的 activity 返回堆栈。
- 任何媒体播放都会停止。
- 与前台服务相关联的通知会被移除。
- 您的应用仍会保留在历史记录中。
- 已安排的作业会在计划的时间执行。
- 闹钟会在预定的时间或时间范围响起。
要测试您的应用在用户停止运行时和之后是否按预期运行, 应用中,请在终端窗口中运行以下 ADB 命令:
adb shell cmd activity stop-app PACKAGE_NAME
豁免
系统会针对特定类型的应用提供几种级别的豁免,下面几部分将介绍这些豁免。
豁免针对的是应用而不是进程。如果系统豁免了应用中的一个进程,则该应用中的所有其他进程也会被豁免。
完全不会显示在任务管理器中
以下应用可以运行前台服务,并且不会显示在 任务管理器:
- 系统级应用
- 安全应用,即具有
ROLE_EMERGENCY
角色的应用 - 处于演示模式的设备上的应用
免于被用户停止
当以下类型的应用运行前台服务时,它们会显示在 但任务管理器旁边没有停止按钮, 供用户点按的应用名称:
- 设备所有者应用
- 资料所有者应用
- 常驻应用
- 具有
ROLE_DIALER
角色的应用
使用专门构建的 API 而不是前台服务
对于很多应用场景,您可以使用平台 API 或 Jetpack API 完成工作 否则您可能需要使用前台服务如果有合适的 专用 API,因此您几乎应始终使用它,而不是使用前台 服务。专门构建的 API 通常提供其他特定于用例的 API 您必须自行构建这些功能。例如: Bubbles API 可处理 需要实现聊天气泡功能的即时通讯应用。
前台服务类型的相关文档列出了相关情况 用来替代前台服务的理想替代方案。
与从后台启动前台服务相关的限制
以 Android 12 或更高版本为目标平台的应用无法启动前台
除了一些特殊的 API 之外,
支持请求。如果应用尝试启动
前台服务,而应用在后台运行时;
无法满足任何特殊情况,则系统会抛出
ForegroundServiceStartNotAllowedException
。
此外,如果应用要启动一项前台服务 使用时的权限(例如身体传感器、摄像头、麦克风或 地点 权限),则无法在应用在后台运行时创建相应服务; 即使应用属于后台启动豁免的某一类 限制。对 启动在使用时需要的前台服务 权限。
不受后台启动限制的约束
在以下情况下,您的应用可以启动前台服务,即使 您的应用将在后台运行:
- 您的应用从用户可见的某种状态(如 activity)过渡。
- 您的应用可以从后台启动 activity,但该应用在现有任务的返回堆栈中具有 activity 的情况除外。
您的应用收到 Firebase Cloud 发出的高优先级消息 消息。
您的应用是设备的当前输入源 方法。
设备重新启动并在广播接收器中接收
ACTION_BOOT_COMPLETED
、ACTION_LOCKED_BOOT_COMPLETED
或ACTION_MY_PACKAGE_REPLACED
intent 操作之后。您的应用在广播接收器中接收
ACTION_TIMEZONE_CHANGED
、ACTION_TIME_CHANGED
或ACTION_LOCALE_CHANGED
intent 操作。您的应用会收到
ACTION_TRANSACTION_DETECTED
事件,来自NfcService
。您的应用使用配套设备管理器并声明了
REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND
权限或REQUEST_COMPANION_RUN_IN_BACKGROUND
权限。请尽可能使用REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND
。您的应用存储
SYSTEM_ALERT_WINDOW
权限。用户停用了应用的电池优化功能。
对启动需要在使用时需要权限的前台服务实施了限制
在 Android 14(API 级别 34)或更高版本中,需要注意一些特殊情况 如果您要启动的前台服务需要在使用时获得权限,则会显示此图标。
如果您的应用以 Android 14 或更高版本为目标平台,那么操作系统
请在创建前台服务时进行检查,以确保应用具备
相应服务类型的适当权限例如,当您创建
前台服务类型
麦克风、
系统会验证您的应用目前
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
(通过 一个不同的可见应用 - 该服务由符合设备规范的应用启动 控制器。
- 该服务由提供
VoiceInteractionService
的应用启动。 - 该服务由具有
START_ACTIVITIES_FROM_BACKGROUND
特许权限。
确定应用中的哪些服务受到影响
测试您的应用时,请启动其前台服务。如果启动的服务对位置信息、麦克风和摄像头的访问受到限制,Logcat 中就会显示以下消息:
Foreground service started from background can not have \ location/camera/microphone access: service SERVICE_NAME