如何在Flutter应用中实现通话录制功能?求解决方案与技术指导
Flutter通话录制功能实现方案
一、可用的Flutter插件
目前Flutter生态中有几款可直接复用的通话录制插件,能快速完成功能集成:
- flutter_call_recorder:支持Android和iOS双平台,封装了原生录制逻辑,配置好权限后调用API即可启动/停止录制。
- call_recorder:跨平台基础录制工具,支持自定义录制文件格式和存储路径。
使用插件前必须配置对应权限:
- Android:在
AndroidManifest.xml中添加RECORD_AUDIO、READ_PHONE_STATE权限;Android 10及以上需额外申请CALL_RECORDING权限(部分国产厂商有更严格的权限管控,需单独适配)。 - iOS:在
Info.plist中添加NSMicrophoneUsageDescription权限说明,iOS通话录制依赖CallKit框架,部分场景需向苹果申请特殊权限。
二、不依赖第三方插件的实现方式
如果不想依赖第三方插件,可通过Flutter原生通道(MethodChannel) 自行对接原生代码实现:
Flutter端代码示例
import 'package:flutter/services.dart'; class CustomCallRecorder { static const MethodChannel _channel = MethodChannel('custom_call_recorder'); // 启动录制,返回是否成功 static Future<bool> startRecording() async { try { return await _channel.invokeMethod<bool>('startRecording') ?? false; } on PlatformException catch (e) { print("启动录制失败: ${e.details}"); return false; } } // 停止录制,返回录制文件路径 static Future<String?> stopRecording() async { try { return await _channel.invokeMethod<String>('stopRecording'); } on PlatformException catch (e) { print("停止录制失败: ${e.details}"); return null; } } }
Android端原生代码(Kotlin)
在MainActivity.kt中实现MethodChannel逻辑处理:
import android.media.MediaRecorder import android.os.Environment 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 = "custom_call_recorder" private var recorder: MediaRecorder? = null private var recordingFile: File? = null override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result -> when (call.method) { "startRecording" -> { val success = startRecording() result.success(success) } "stopRecording" -> { val filePath = stopRecording() result.success(filePath) } else -> result.notImplemented() } } } private fun startRecording(): Boolean { return try { recordingFile = File( getExternalFilesDir(Environment.DIRECTORY_MUSIC), "call_rec_${System.currentTimeMillis()}.mp4" ) recorder = MediaRecorder().apply { setAudioSource(MediaRecorder.AudioSource.VOICE_CALL) setOutputFormat(MediaRecorder.OutputFormat.MPEG_4) setAudioEncoder(MediaRecorder.AudioEncoder.AAC) setOutputFile(recordingFile?.absolutePath) prepare() start() } true } catch (e: Exception) { e.printStackTrace() false } } private fun stopRecording(): String? { return try { recorder?.stop() recorder?.release() recorder = null recordingFile?.absolutePath } catch (e: Exception) { e.printStackTrace() null } } }
iOS端原生代码(Swift)
在AppDelegate.swift中实现录制逻辑:
import UIKit import Flutter import AVFoundation @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { private let CHANNEL = "custom_call_recorder" var recorder: AVAudioRecorder? override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { let controller : FlutterViewController = window?.rootViewController as! FlutterViewController let channel = FlutterMethodChannel(name: CHANNEL, binaryMessenger: controller.binaryMessenger) channel.setMethodCallHandler({ [weak self] (call: FlutterMethodCall, result: FlutterResult) -> Void in guard let self = self else { return } switch call.method { case "startRecording": self.startRecording(result: result) case "stopRecording": self.stopRecording(result: result) default: result(FlutterMethodNotImplemented) } }) GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } private func startRecording(result: FlutterResult) { let session = AVAudioSession.sharedInstance() do { try session.setCategory(.playAndRecord, mode: .default) try session.setActive(true) let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] let filePath = "\(documentsPath)/call_rec_\(Date().timeIntervalSince1970).m4a" let url = URL(fileURLWithPath: filePath) let settings = [ AVFormatIDKey: Int(kAudioFormatMPEG4AAC), AVSampleRateKey: 44100.0, AVNumberOfChannelsKey: 2, AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue ] recorder = try AVAudioRecorder(url: url, settings: settings) recorder?.record() result(true) } catch { result(FlutterError(code: "RECORD_ERROR", message: error.localizedDescription, details: nil)) } } private func stopRecording(result: FlutterResult) { recorder?.stop() recorder = nil let session = AVAudioSession.sharedInstance() do { try session.setActive(false) result(nil) // 可修改为返回文件路径,此处简化处理 } catch { result(FlutterError(code: "STOP_ERROR", message: error.localizedDescription, details: nil)) } } }
三、替代方案(生态内不可行时)
- 引导使用系统录制功能:Android 10+和iOS均自带通话录制功能,可通过应用引导用户手动开启,规避权限和兼容性问题。
- 集成第三方通话服务:如Twilio、Agora等,这类服务提供自带的通话录制API,无需处理原生权限限制,但需依赖其SDK重构通话模块。
四、关键注意事项
- Android部分厂商(如小米、华为)对通话录制有额外限制,需覆盖主流机型测试兼容性。
- iOS通话录制需配合CallKit框架,App Store审核时需明确说明录制用途,确保符合隐私法规。
- 所有录制行为必须提前告知用户并获得明确同意,符合GDPR、国内隐私法等合规要求。
内容的提问来源于stack exchange,提问作者Guru Subramani
相关产品推荐
相关产品推荐

