Android14前台服务适配指南
Android14前台服务适配指南
Android 10引入了android:foregroundServiceType属性,用于帮助开发者更有目的地定义前台服务。这个属性在Android 14中被强制要求,必须指定适当的前台服务类型。以下是可选择的前台服务类型:
- camera: 相机应用。
- connectedDevice: 与连接的设备相关的应用。
- dataSync: 数据同步应用。
- health: 与健康相关的应用。
- location: 位置相关的应用。
- mediaPlayback: 媒体播放应用。
- mediaProjection: 媒体投影应用。
- microphone: 麦克风相关的应用。
- phoneCall: 电话呼叫应用。
- remoteMessaging: 远程消息应用。
- shortService: 短期服务应用。
- specialUse: 特殊用途应用。
- systemExempted: 系统例外应用。
如果应用的前台服务与上述类型无关,建议迁移到使用WorkManager或用户触发的数据传输作业等其他方式。
值得注意的是,Android 14中新增了health、remoteMessaging、shortService、specialUse和systemExempted类型。应用在清单文件中必须声明前台服务类型,如下所示:
对于以Android 14为目标平台的应用,如果没有定义前台服务类型,系统将在调用startForeground()时引发MissingForegroundServiceTypeException异常。这一变化旨在提高应用的安全性和用户隐私保护。
Android14前台服务适配
-
声明新权限:以Android 14为目标平台的应用使用前台服务类型时,必须根据前台服务类型声明特定的权限。这些权限列在每种前台服务类型的预期用例和强制执行部分中,并被标记为“您必须在清单文件中声明的权限”。这些权限都是一般权限,无法被用户撤销。如果应用调用startForeground()但未声明适当的前台服务类型权限,系统将引发SecurityException异常。
-
运行时包含前台服务类型:对于启动前台服务的应用,建议使用startForeground()的重载版本,可以在其中传递一个或多个前台服务类型的值。通常,应该只声明与特定用例相关的前台服务类型。如果某个前台服务以多个类型启动,应该遵守所有类型的强制执行要求。
-
系统运行时检查:系统会检查前台服务类型的使用是否合适,并验证应用是否已请求适当的运行时权限或使用所需的API。例如,应用使用FOREGROUND_SERVICE_TYPE_LOCATION前台服务类型时,需要请求ACCESS_COARSE_LOCATION或ACCESS_FINE_LOCATION权限。应用必须严格遵循请求权限和启动前台服务的特定顺序。在调用startForeground()之前,必须先请求并获得所需的权限。如果应用不满足前台服务的运行时要求,在调用startForeground()后,系统将抛出SecurityException,这可以防止前台服务启动,可能导致应用崩溃。
每种前台服务类型的预期用例和强制执行部分提供了有关平台强制执行要求的详细信息,应用开发者应按照这些规定来使用前台服务类型以确保应用的正常运行。
每种前台服务类型的预期用例和强制执行
仅就摄像头、连接的设备、数据同步等几项服务,说明前台服务用法,更多类型使用请参考下面链接。
https://developer.android.google.cn/about/versions/14/changes/fgs-types-required?hl=zh-cn
要使用特定的前台服务类型,应满足以下条件:
-
在清单文件中声明特定权限。
-
满足特定的运行时要求。
-
应用必须满足该类型的其中一组预期用例。
具体前台服务类型的要求如下:
-
摄像头:
- 声明权限:FOREGROUND_SERVICE_CAMERA。
- 运行时要求:请求相机运行时权限。
- 用例:继续在后台访问相机,如支持多任务的视频聊天应用。
-
连接的设备:
- 声明权限:FOREGROUND_SERVICE_CONNECTED_DEVICE。
- 运行时要求:必须满足特定权限或运行时权限。
- 用例:与需要蓝牙、NFC、IR、USB或网络连接的外部设备进行互动。用例可以包括蓝牙连接、网络连接等。
-
数据同步:
- 声明权限:FOREGROUND_SERVICE_DATA_SYNC。
- 运行时要求:无。
- 用例:数据传输操作,如数据上传、备份、导入导出、文件处理等。这个前台服务类型将被废弃,建议使用WorkManager或用户发起的数据传输作业。
-
健康(预览版,Android 14新增):
- 声明权限:FOREGROUND_SERVICE_HEALTH。
- 运行时要求:必须满足特定权限或运行时权限。
- 用例:为健身类别的应用提供支持的长时间运行用例,如健身追踪器。
-
位置:
- 声明权限:FOREGROUND_SERVICE_LOCATION。
- 运行时要求:请求位置信息使用权限,包括ACCESS_COARSE_LOCATION或ACCESS_FINE_LOCATION。
- 用例:长时间运行的位置信息用例,如导航和位置信息分享。
满足这些前台服务类型的要求是确保应用能够正常使用相关功能的关键。开发者应在清单文件和运行时权限请求中遵循这些规定,以确保应用能够以前台服务类型的方式正常运行。
前台服务用于用户数据传输业务
在 Android 14 中,前台服务规则更严格,要求应用满足条件才能使用前台服务。引入新 API 指定用户发起的数据传输作业,适用于长时间数据传输。这类作业需要用户手动启动,具备 RUN_USER_INITIATED_JOBS 权限。改进旨在提高系统稳定性和用户体验。
开启用户作业
要运行用户发起的作业,请执行以下步骤:
- 在清单文件中声明 RUN_USER_INITIATED_JOBS 权限:
...
- 在构建 JobInfo 对象时,使用新的 setUserInitiated() 和 setDataTransfer() 方法。建议您提供预估的载荷大小,可以使用 setEstimatedNetworkBytes() 方法:
val networkRequestBuilder = NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) val jobInfo = JobInfo.Builder() // ... .setUserInitiated(true) .setDataTransfer(true) .setRequiredNetwork(networkRequestBuilder.build()) .setEstimatedNetworkBytes(1024 * 1024 * 1024) // ... .build()
- 在应用可见时或满足允许的条件时调度作业:
val jobScheduler: JobScheduler = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler jobScheduler.schedule(jobInfo)
- 执行作业时,请确保为 JobService 对象调用 setNotification(),用于通知用户作业正在运行:
val notification = Notification.Builder(applicationContext, NOTIFICATION_CHANNEL_ID) .setContentTitle("My user-initiated data transfer job") .setSmallIcon(android.R.mipmap.myicon) .setContentText("Job is running") .build() class CustomJobService : JobService() { override fun onStartJob(params: JobParameters?): Boolean { setNotification(params, notification.id, notification, JobService.JOB_END_NOTIFICATION_POLICY_DETACH) // 执行作业任务。 } }
-
请注意,如果未及时调用 setNotification(),可能导致应用出现 ANR。
-
定期更新通知,以便用户了解作业的状态和进度。如果在安排作业之前无法确定传输大小,请在了解传输大小后使用新的 API updateEstimatedNetworkBytes() 更新传输大小。
-
在作业执行完成后,调用 jobFinished() 以向系统表明作业已完成,或者需要重新调度作业。
停止用户作业
-
停止用户发起的数据传输作业:
- 用户和系统都可以停止用户发起的传输作业。
- 用户可以通过任务管理器中的 Stop 操作来停止用户发起的传输作业。
- 当用户停止作业时,系统会终止应用的进程,包括所有正在运行的作业或前台服务。
- 系统不会调用 onStopJob() 来终止作业,也会阻止重新调度用户可见的作业。
- 建议在发布的作业通知中提供控件,以方便用户停止和重新调度作业。
- 在某些情况下,任务管理器中可能不会显示 Stop 按钮或作业根本不会出现。
-
系统提供的停止作业:
- 与常规作业不同,用户发起的数据传输作业不受应用待机模式存储分区配额的影响。
- 但是,系统仍会停止作业,原因包括:
- 不再满足开发者定义的约束条件。
- 系统认为该作业的运行时间超出了完成数据传输所需的时间。
- 系统需要优先考虑系统运行状况,可能由于设备温度过高而停止作业。
- 应用进程因设备内存不足而被终止。
- 当系统停止作业时(不是因内存不足),系统会调用 onStopJob(),并在系统认为最佳的时间重试作业。
- 开发者应确保应用能够保留数据传输状态,即使未调用 onStopJob(),并在再次调用 onStartJob() 时能够恢复状态。
用户作业约束条件
总结如下:
-
为了支持在最佳时间点运行的作业,Android 提供了能够为每种作业类型分配约束条件的功能,这一功能从 Android 13 开始可用。
-
用户发起的数据传输作业允许使用的约束条件包括:
- setBackoffCriteria(JobInfo.BACKOFF_POLICY_EXPONENTIAL)
- setClipData()
- setEstimatedNetworkBytes()
- setMinimumNetworkChunkBytes()
- setPersisted()
- setNamespace()
- setRequiredNetwork()
- setRequiredNetworkType()
- setRequiresBatteryNotLow()
- setRequiresCharging()
- setRequiresStorageNotLow()
测试
测试应用作业的步骤包括:
- 获取作业 ID。
- 通过命令 adb shell cmd jobscheduler run -f APP_PACKAGE_NAME JOB_ID 可以立即运行或重试已停止的作业。
- 通过命令 adb shell cmd jobscheduler timeout TEST_APP_PACKAGE TEST_JOB_ID 可以模拟系统强行停止作业,例如因系统运行状况或超出配额条件。