安卓 14 权限适配
更新时间: 2024/08/05 14:13:38
本文介绍网易云信音视频通话 SDK(NERTC SDK)安卓版本在安卓 14 及其以上的系统版本上需要修改的前台服务权限适配。
适用场景
Android 14(代号为翻转蛋糕)是谷歌于 2023 年 10 月 4 日正式发布的 Android 操作系统,并将源代码推送到 Android 开源项目(AOSP)。
从 Android 14 版本开始,Android 系统要求应用明确指定必须使用的前台服务类型。如果您将应用的 targetSdkVersion
设置为 34 或更高,则在 Android 14 或更高版本设备上运行时,系统将执行兼容性检查,以验证应用是否已正确声明其前台服务类型。
如果应用未正确集成前台服务,可能会出现:
-
设备在短时间锁屏时,远端用户音频无声或看不到视频。
-
应用在运行过程中切换到后台时,远端用户音频无声。
targetSdk 版本要求
targetSdkVersion
是 Android 应用开发中的一个重要概念,它用于指定应用的目标 SDK 版本。这个属性告诉 Android 系统您的应用已经测试并准备好支持的最高 API 级别。
在 Android 14 上,为了保障用户的手机安全,要求新安装的应用的 targetSdkVersion
需要大于等于 23(即 Android 6.0 及以上),小于这个值将无法在 Android 14 的设备上面安装。
前台服务类型要求
-
当
targetSDKVersion
为 34,在Service
中调用了startForeground
方法,要求应用在开启前台服务的时候,注明这个前台服务的用途,否则系统会抛出MissingForegroundServiceTypeException
异常,其中和媒体相关的用途分类有:用途 说明 清单文件权限要求 运行时要求 摄像头 继续在后台访问相机,例如支持多任务的视频聊天应用。 FOREGROUND_SERVICE_CAMERA
请求 CAMERA 运行时权限。 媒体 在后台继续播放音频或视频。在 Android TV 上支持数字视频录制(DVR)功能。 FOREGROUND_SERVICE_MEDIA_PLAYBACK
无 媒体投影 使用 MediaProjection
API 将内容投影到非主要显示屏或外部设备。这些内容不必全都为媒体内容。不包括 Cast SDK。FOREGROUND_SERVICE_MEDIA_PROJECTION
调用 createScreenCaptureIntent()
方法。麦克风 在后台继续捕获麦克风内容,例如录音器或通信应用。 FOREGROUND_SERVICE_MICROPHONE
请求 RECORD_AUDIO
运行时权限。 -
适配前台服务类型的特性方式具体有两种方式,一种是注册清单属性,另一种是代码动态注册。
-
方式一:
XML
//注册清单属性 <service android:name=".XxxService" android:foregroundServiceType="dataSync" android:exported="false"> </service>
-
方式二:
Java
startForeground(xxx, xxx, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC);
-
-
前台服务类型对应的适配属性。
用途 清单文件属性值 Java 常量值 摄像头 camera ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA 媒体 mediaPlayback ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK 媒体投影 mediaProjection ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION 麦克风 microphone ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE
权限适配方式
-
在
AndroidManifest.xml
文件中,声明前台服务权限 (FOREGROUND_SERVICE
),并设置前台服务类型 (foregroundServiceType
),以实现实时音视频互动 App 所需的功能,通常需要包括麦克风 (microphone
)、摄像头(camera
)和媒体播放(mediaPlayback
)服务类型。以下是示例代码:XML
<manifest ...> <!-- 声明前台服务权限 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <application ...> ... <!-- 指定前台服务类型 --> <service android:name=".YourForegroundService" android:foregroundServiceType="microphone|camera|mediaPlayback" /> ... </application> </manifest>
-
创建服务后,使用以下示例代码调用
startForeground
方法将指定服务提升为前台服务:Java
@Override public void onCreate() { super.onCreate(); // 获取默认的通知 Notification notification = getDefaultNotification(); try { // 根据 Android 版本,选择合适的方式处理前台服务 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { // 对于 Android 11 及以上版本,启动前台服务并指定多种服务类型 int serviceTypes = ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE | ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA | ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK; this.startForeground(NOTIFICATION_ID, notification, serviceTypes); } else { // 对于 Android 11 以下版本,无需指定服务类型,简单地启动前台服务即可 this.startForeground(NOTIFICATION_ID, notification); } } catch (Exception ex) { Log.e(TAG, "Error starting foreground service", ex); } }
-
当应用切换到后台时,使用以下示例代码调用
startForegroundService
方法来启动服务,以确保服务持续运行:Java
@Override public void onPause() { super.onPause(); startRecordingService(); } private void startRecordingService() { if (joined) { // 创建一个 intent Intent intent = new Intent(requireContext(), LocalRecordingService.class); // 根据 Android 版本,选择合适的方式启动前台服务 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // 对于 Android 8 及以上版本,使用 startForegroundService 来启动服务 requireContext().startForegroundService(intent); } else { // 对于 Android 8 以下版本,使用 startService 来启动服务 requireContext().startService(intent); } } }