安卓 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 的设备上面安装。

前台服务类型要求

  1. 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 运行时权限。
  2. 适配前台服务类型的特性方式具体有两种方式,一种是注册清单属性,另一种是代码动态注册。

    • 方式一:

      XML//注册清单属性
      <service
        android:name=".XxxService"
        android:foregroundServiceType="dataSync"
        android:exported="false">
      </service>
      
    • 方式二:

      JavastartForeground(xxx, xxx, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC);
      
  3. 前台服务类型对应的适配属性。

    用途 清单文件属性值 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

权限适配方式

  1. 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>
    
  2. 创建服务后,使用以下示例代码调用 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);
        }
    }
    
  3. 当应用切换到后台时,使用以下示例代码调用 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);
            }
        }
    }
    
此文档是否对你有帮助?
有帮助
去反馈
  • 适用场景
  • targetSdk 版本要求
  • 前台服务类型要求
  • 权限适配方式