You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android 14+(SDK34)使用MediaProjection启动前台服务遇SecurityException

Android 15设备启动前台服务触发SecurityException崩溃问题

崩溃错误信息

由java.lang.SecurityException引起:启动类型为microphone的前台服务(FGS),调用应用ProcessRecord{6d0f21f 24588:com.app.freeboomshare/u0a271},targetSDK=34,需要满足以下权限要求:必须拥有所有allOf=true的权限[android.permission.FOREGROUND_SERVICE_MICROPHONE],且拥有任意一个allOf=false的权限[android.permission.CAPTURE_AUDIO_HOTWORD, android.permission.CAPTURE_AUDIO_OUTPUT, android.permission.CAPTURE_MEDIA_OUTPUT, android.permission.CAPTURE_TUNER_AUDIO_INPUT, android.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT, android.permission.RECORD_AUDIO],同时应用必须处于符合条件的状态/豁免范围才能访问前台专属权限

背景信息

应用已上线Google Play,通过MediaProjection + 前台服务实现屏幕和音频录制功能,targetSdkVersion设为34。崩溃发生在启动前台服务后、屏幕录制开始前。

AndroidManifest.xml权限配置

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> 
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" /> 
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" /> 
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" /> 
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> 
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> 
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA" />

已尝试方案

  • 确认RECORD_AUDIO和FOREGROUND_SERVICE权限已通过运行时授权
  • 添加Android 15(UpsideDownCake)适配的前台服务启动逻辑:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { 
    // 同时录制屏幕、音频和摄像头
    val serviceTypes = ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION or 
                      ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE or 
                      ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA 
    startForeground(1, notification, serviceTypes) 
} else { 
    startForeground(1, notification) 
}

Fragment核心代码

private fun startRecording() {
    val mediaProjectionManager = requireActivity().getSystemService(AppCompatActivity.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
    startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), REQUEST_CODE)
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == REQUEST_CODE) {
        if (resultCode == AppCompatActivity.RESULT_OK && data != null) {
            RecordingUtils.startCountdown(viewBinding.countdownText) {
                viewBinding.btStopRecording.visibility = View.VISIBLE
                val serviceIntent = Intent(
                    requireActivity(),
                    ScreenCameraReordingService::class.java
                )
                serviceIntent.action = ACTION_START_RECORDING
                serviceIntent.putExtra(EXTRA_RESULT_CODE, resultCode)
                serviceIntent.putExtra(EXTRA_RESULT_DATA, data)
                serviceIntent.putExtra("isAudioRecordingON", isAudioRecordingON)
                serviceIntent.putExtra("isCameraRecordingON", isCameraRecordingON)
                ContextCompat.startForegroundService(requireActivity(), serviceIntent)
                disableToggles()
            }
        } else {
            viewBinding.btStartRecording.visibility = View.VISIBLE
            viewBinding.btStopRecording.visibility = View.GONE
            viewModel.startScreenRecordingClickLiveData.value = false
            Toast.makeText(requireActivity(), "Screen capture permission denied", Toast.LENGTH_SHORT).show()
        }
    }
    /*else if (requestCode == REQUEST_CODE_OVERLAY && resultCode == AppCompatActivity.RESULT_OK){
        val intent = Intent(requireContext(), ScreenCameraReordingService::class.java).apply {
            action = ScreenCameraReordingService.ACTION_START_OVERLAY
        }
        requireContext().startForegroundService(intent)
    }*/
}

问题分析与修复方案

核心问题

Android 15对前台服务的权限验证逻辑更严格:启动包含MICROPHONE类型的前台服务时,除了声明FOREGROUND_SERVICE_MICROPHONE权限,还需满足两个关键条件:

  1. 必须持有RECORD_AUDIO(或其他指定音频权限)的运行时授权
  2. 服务启动必须由即时用户交互触发(比如直接点击按钮,而非延迟操作)

另外你的Manifest中缺少RECORD_AUDIO权限声明,这是运行时授权的前提。

具体修复步骤

  1. 补全Manifest权限声明
    在Manifest中添加RECORD_AUDIO权限:

    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    
  2. 提前检查并请求必要权限
    在调用startRecording()前,先检查并请求录音、摄像头权限,确保授权完成后再进入流程:

    private fun checkPermissionsAndStart() {
        val requiredPermissions = mutableListOf<String>()
        // 检查录音权限
        if (isAudioRecordingON && ContextCompat.checkSelfPermission(requireActivity(), Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
            requiredPermissions.add(Manifest.permission.RECORD_AUDIO)
        }
        // 检查摄像头权限
        if (isCameraRecordingON && ContextCompat.checkSelfPermission(requireActivity(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            requiredPermissions.add(Manifest.permission.CAMERA)
        }
        if (requiredPermissions.isNotEmpty()) {
            ActivityCompat.requestPermissions(requireActivity(), requiredPermissions.toTypedArray(), REQUEST_PERMISSION_CODE)
        } else {
            startRecording()
        }
    }
    

    在onRequestPermissionsResult中处理授权结果,通过后再执行startRecording()。

  3. 按需配置前台服务类型
    根据实际录制需求动态设置serviceTypes,避免添加不需要的类型触发额外权限检查:

    val serviceTypes = buildList {
        add(ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION)
        if (isAudioRecordingON) add(ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE)
        if (isCameraRecordingON) add(ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA)
    }.reduce { acc, type -> acc or type }
    startForeground(1, notification, serviceTypes)
    
  4. 确保服务启动时机符合要求
    Android 15要求前台服务必须由即时用户交互触发,建议将前台服务启动逻辑调整到用户点击"开始录制"的直接回调中,避免通过倒计时等延迟操作触发。如果必须保留倒计时,需确保倒计时的触发紧接用户操作,且倒计时时长不宜过长。

内容的提问来源于stack exchange,提问作者Mansi Shah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 18:54:51