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

如何在Android设备的Flutter应用中合规录制内部音频?

Android非Root实现Flutter内部音频录制方案

核心可行性说明

Android 10(API 29)及以上版本提供了MediaProjection API,这是官方支持的非Root录屏/内部音频录制方案,无需Root权限,仅需用户通过系统弹窗授权。Android 9及以下版本无官方非Root实现途径,只能引导用户升级系统或使用系统自带录制功能。

Flutter实现方式

1. 自定义原生代码(可控性强,推荐)

通过Flutter的MethodChannel与Android原生层通信,调用MediaProjection API实现录制。

Flutter侧代码

import 'package:flutter/services.dart';

class InternalAudioRecorder {
  static const MethodChannel _channel = MethodChannel('internal_audio_recorder');

  // 请求MediaProjection授权
  static Future<bool> requestPermission() async {
    try {
      return await _channel.invokeMethod('requestPermission');
    } on PlatformException catch (_) {
      return false;
    }
  }

  // 开始录制(传入输出文件路径)
  static Future<void> startRecording(String outputPath) async {
    try {
      await _channel.invokeMethod('startRecording', {'path': outputPath});
    } on PlatformException catch (_) {
      rethrow;
    }
  }

  // 停止录制
  static Future<void> stopRecording() async {
    try {
      await _channel.invokeMethod('stopRecording');
    } on PlatformException catch (_) {
      rethrow;
    }
  }
}

Android原生侧代码(Kotlin)

import android.content.Intent
import android.media.MediaRecorder
import android.media.projection.MediaProjectionManager
import android.os.Build
import android.os.Environment
import android.widget.Toast
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import java.io.File

class MainActivity : FlutterActivity() {
    private val CHANNEL = "internal_audio_recorder"
    private var mediaProjectionManager: MediaProjectionManager? = null
    private var mediaProjection: android.media.projection.MediaProjection? = null
    private var mediaRecorder: MediaRecorder? = null
    private val REQUEST_CODE = 1000

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
            when (call.method) {
                "requestPermission" -> {
                    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
                        Toast.makeText(this, "仅支持Android 10及以上版本", Toast.LENGTH_SHORT).show()
                        result.success(false)
                        return@setMethodCallHandler
                    }
                    mediaProjectionManager = getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
                    val intent = mediaProjectionManager?.createScreenCaptureIntent()
                    startActivityForResult(intent, REQUEST_CODE)
                    result.success(true)
                }
                "startRecording" -> {
                    val path = call.argument<String>("path") ?: "${Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC)}/internal_audio.mp4"
                    startRecording(path)
                    result.success(null)
                }
                "stopRecording" -> {
                    stopRecording()
                    result.success(null)
                }
                else -> result.notImplemented()
            }
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == REQUEST_CODE) {
            if (resultCode == RESULT_OK && data != null) {
                mediaProjection = mediaProjectionManager?.getMediaProjection(resultCode, data)
            } else {
                Toast.makeText(this, "授权失败,无法录制音频", Toast.LENGTH_SHORT).show()
            }
        }
    }

    private fun startRecording(outputPath: String) {
        mediaRecorder = MediaRecorder().apply {
            // 配置录制参数(必须包含视频源,因为MediaProjection绑定录屏逻辑)
            setVideoSource(MediaRecorder.VideoSource.SURFACE)
            setAudioSource(MediaRecorder.AudioSource.REMOTE_SUBMIX)
            setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
            setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
            setVideoEncoder(MediaRecorder.VideoEncoder.H264)
            setOutputFile(outputPath)
            setVideoSize(1280, 720) // 任意分辨率,仅为满足录屏要求
            setVideoFrameRate(30)

            try {
                prepare()
            } catch (e: Exception) {
                Toast.makeText(this@MainActivity, "录制初始化失败", Toast.LENGTH_SHORT).show()
                return
            }
        }

        // 创建虚拟显示,绑定MediaRecorder的Surface
        mediaProjection?.createVirtualDisplay(
            "AudioRecordingDisplay",
            1280, 720,
            resources.displayMetrics.densityDpi,
            android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
            mediaRecorder?.surface,
            null,
            null
        )

        mediaRecorder?.start()
        Toast.makeText(this, "开始录制", Toast.LENGTH_SHORT).show()
    }

    private fun stopRecording() {
        mediaRecorder?.run {
            stop()
            release()
        }
        mediaProjection?.stop()
        mediaRecorder = null
        mediaProjection = null
        Toast.makeText(this, "录制结束", Toast.LENGTH_SHORT).show()
    }
}

AndroidManifest权限配置

<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <!-- Android 13+ 必需 -->

2. 第三方插件(快速实现)

可使用现成的Flutter插件如screen_recorder,这类插件已封装好MediaProjection逻辑,只需调用API即可。注意选择维护活跃、支持音频录制的版本,使用前需验证兼容性。

隐私合规与最佳实践

  • 明确告知用户:在应用内清晰说明录制内部音频的用途,获取用户主动同意,避免误导。
  • 系统授权:必须通过系统的MediaProjection授权弹窗获取权限,禁止绕过系统授权逻辑。
  • 录制限制:仅录制用户明确需要的内容,禁止录制敏感信息(如通话、支付界面音频)。
  • 文件处理:录制的音频文件仅允许用户本地保存或自行分享,未经用户同意不得上传至服务器。
  • 前台服务:Android 10+要求录制过程中显示前台通知,告知用户当前正在录制,避免后台静默录制。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 03:22:02