Flutter实现连续语音转文字的永久解决方案求助
Flutter 连续语音转文字永久解决方案
方案一:Android原生集成(Kotlin实现连续识别)
Android系统自带的SpeechRecognizer支持连续语音识别模式,不需要每次停止重启会话,稳定性和效率远高于手动重启的临时方案。
实现步骤:
- 在Android项目的
MainActivity.kt中初始化SpeechRecognizer并配置连续识别参数:
import android.speech.RecognitionListener import android.speech.SpeechRecognizer import android.speech.RecognizerIntent import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel import android.os.Bundle class MainActivity : FlutterActivity() { private val CHANNEL = "com.yourapp.speech" private lateinit var speechRecognizer: SpeechRecognizer override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result -> when (call.method) { "startContinuousListening" -> { startContinuousRecognition() result.success(true) } "stopListening" -> { speechRecognizer.stopListening() result.success(true) } } } initSpeechRecognizer() } private fun initSpeechRecognizer() { speechRecognizer = SpeechRecognizer.createSpeechRecognizer(this) speechRecognizer.setRecognitionListener(object : RecognitionListener { override fun onResults(resultsBundle: Bundle?) { val matches = resultsBundle?.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION) matches?.firstOrNull()?.let { result -> MethodChannel(flutterEngine?.dartExecutor?.binaryMessenger, CHANNEL) .invokeMethod("onRecognitionResult", result) } // 识别完成后自动重启监听,实现连续转录 speechRecognizer.startListening(createContinuousIntent()) } override fun onError(errorCode: Int) { // 非无匹配错误时重启监听 if (errorCode != SpeechRecognizer.ERROR_NO_MATCH) { speechRecognizer.startListening(createContinuousIntent()) } } // 以下为接口默认实现 override fun onReadyForSpeech(params: Bundle?) {} override fun onBeginningOfSpeech() {} override fun onRmsChanged(rmsdB: Float) {} override fun onBufferReceived(buffer: ByteArray?) {} override fun onEndOfSpeech() {} override fun onPartialResults(partialResults: Bundle?) {} override fun onEvent(eventType: Int, params: Bundle?) {} }) } private fun createContinuousIntent(): Intent { val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH) intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM) intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault()) // 设置连续识别参数,避免短暂静音就停止识别 intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS, 3000) intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000) return intent } private fun startContinuousRecognition() { speechRecognizer.startListening(createContinuousIntent()) } override fun onDestroy() { super.onDestroy() speechRecognizer.destroy() } }
- Flutter端通过
MethodChannel调用原生方法并接收结果:
import 'package:flutter/services.dart'; class SpeechService { static const MethodChannel _channel = MethodChannel('com.yourapp.speech'); static Function(String)? onResultCallback; static void init() { _channel.setMethodCallHandler((call) async { if (call.method == 'onRecognitionResult') { onResultCallback?.call(call.arguments as String); } return null; }); } static Future<void> startContinuousListening() async { await _channel.invokeMethod('startContinuousListening'); } static Future<void> stopListening() async { await _channel.invokeMethod('stopListening'); } }
方案二:iOS原生集成(Swift实现连续识别)
iOS的SFSpeechRecognizer支持连续转录,通过SFSpeechAudioBufferRecognitionRequest持续推送音频流实现连续识别,还可开启离线识别降低成本。
实现步骤:
- 在iOS项目的
AppDelegate.swift中添加语音识别逻辑:
import UIKit import Flutter import Speech @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { private let CHANNEL = "com.yourapp.speech" private var speechRecognizer: SFSpeechRecognizer? private var recognitionRequest: SFSpeechAudioBufferRecognitionRequest? private var recognitionTask: SFSpeechRecognitionTask? private let audioEngine = AVAudioEngine() override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { let controller = window?.rootViewController as! FlutterViewController let channel = FlutterMethodChannel(name: CHANNEL, binaryMessenger: controller.binaryMessenger) channel.setMethodCallHandler { [weak self] call, result in guard let self = self else { return } switch call.method { case "startContinuousListening": self.startContinuousRecognition(result: result) case "stopListening": self.stopRecognition() result(true) default: result(FlutterMethodNotImplemented) } } speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "zh-CN")) SFSpeechRecognizer.requestAuthorization { authStatus in OperationQueue.main.addOperation { if authStatus != .authorized { // 处理权限拒绝逻辑 } } } GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } private func startContinuousRecognition(result: FlutterResult) { guard let speechRecognizer = speechRecognizer, speechRecognizer.isAvailable else { result(FlutterError(code: "UNAVAILABLE", message: "语音识别不可用", details: nil)) return } if audioEngine.isRunning { audioEngine.stop() recognitionRequest?.endAudio() } let audioSession = AVAudioSession.sharedInstance() do { try audioSession.setCategory(.record, mode: .measurement, options: .duckOthers) try audioSession.setActive(true, options: .notifyOthersOnDeactivation) } catch { result(FlutterError(code: "AUDIO_ERROR", message: "音频会话配置失败", details: error.localizedDescription)) return } recognitionRequest = SFSpeechAudioBufferRecognitionRequest() guard let recognitionRequest = recognitionRequest else { result(FlutterError(code: "REQUEST_ERROR", message: "无法创建识别请求", details: nil)) return } recognitionRequest.shouldReportPartialResults = true recognitionRequest.requiresOnDeviceRecognition = true // 开启离线识别 let inputNode = audioEngine.inputNode let recordingFormat = inputNode.outputFormat(forBus: 0) inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { buffer, _ in recognitionRequest.append(buffer) } audioEngine.prepare() do { try audioEngine.start() } catch { result(FlutterError(code: "ENGINE_ERROR", message: "音频引擎启动失败", details: error.localizedDescription)) return } recognitionTask = speechRecognizer.recognitionTask(with: recognitionRequest) { [weak self] result, error in guard let self = self else { return } var isFinal = false if let result = result { isFinal = result.isFinal let channel = FlutterMethodChannel(name: self.CHANNEL, binaryMessenger: self.window?.rootViewController as! FlutterBinaryMessenger) channel.invokeMethod("onRecognitionResult", arguments: result.bestTranscription.formattedString) } if error != nil || isFinal { self.audioEngine.stop() inputNode.removeTap(onBus: 0) self.recognitionRequest = nil self.recognitionTask = nil // 无错误时自动重启,实现连续转录 if error == nil { self.startContinuousRecognition(result: result) } } } result(true) } private func stopRecognition() { audioEngine.stop() recognitionRequest?.endAudio() recognitionTask?.cancel() recognitionRequest = nil recognitionTask = nil } }
- Flutter端的
MethodChannel代码与Android端通用,直接复用即可。
方案三:使用开源离线语音识别库Vosk
Vosk是完全开源的离线语音识别工具,支持连续转录,提供成熟的Flutter插件,无需依赖在线API,零使用成本,适合面向公众发布。
实现步骤:
- 添加依赖到
pubspec.yaml:
dependencies: vosk_flutter: ^0.3.0
- 下载对应语言的模型(如中文模型),放到项目
assets/vosk-model目录下,在pubspec.yaml声明资源:
assets: - assets/vosk-model/
- Flutter端实现连续识别:
import 'package:vosk_flutter/vosk_flutter.dart'; class VoskSpeechService { static Model? _model; static Recognizer? _recognizer; static Function(String)? onResultCallback; static Future<void> init() async { await VoskFlutter.instance.initialize(); // 加载本地模型 _model = await Model.fromAsset('assets/vosk-model/'); _recognizer = Recognizer( model: _model!, sampleRate: 16000, ); // 监听实时识别结果 _recognizer!.onPartialResult.listen((result) { onResultCallback?.call(result.alternatives.first.word); }); // 监听最终识别结果 _recognizer!.onResult.listen((result) { onResultCallback?.call(result.alternatives.first.word); }); } static Future<void> startListening() async { await _recognizer?.startListening(); } static Future<void> stopListening() async { await _recognizer?.stopListening(); } static Future<void> dispose() async { await _recognizer?.dispose(); await _model?.dispose(); } }
方案对比
- 原生集成:完全可控,稳定性高,依赖系统自带语音识别能力,部分设备支持离线识别,零成本,但需分别维护Android和iOS代码。
- Vosk:完全离线,跨平台识别效果一致,不依赖系统能力,适合对识别一致性要求高的场景,但会增加APK/IPA包体积。
内容的提问来源于stack exchange,提问作者Sannidhya Dubey
相关产品推荐
相关产品推荐

