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

Flutter实现连续语音转文字的永久解决方案求助

Flutter 连续语音转文字永久解决方案

方案一:Android原生集成(Kotlin实现连续识别)

Android系统自带的SpeechRecognizer支持连续语音识别模式,不需要每次停止重启会话,稳定性和效率远高于手动重启的临时方案。

实现步骤:

  1. 在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()
    }
}
  1. 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持续推送音频流实现连续识别,还可开启离线识别降低成本。

实现步骤:

  1. 在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
    }
}
  1. Flutter端的MethodChannel代码与Android端通用,直接复用即可。

方案三:使用开源离线语音识别库Vosk

Vosk是完全开源的离线语音识别工具,支持连续转录,提供成熟的Flutter插件,无需依赖在线API,零使用成本,适合面向公众发布。

实现步骤:

  1. 添加依赖到pubspec.yaml:
dependencies:
  vosk_flutter: ^0.3.0
  1. 下载对应语言的模型(如中文模型),放到项目assets/vosk-model目录下,在pubspec.yaml声明资源:
assets:
  - assets/vosk-model/
  1. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 23:45:38