flutter_baidu_speech_tts 0.0.1
flutter_baidu_speech_tts: ^0.0.1 copied to clipboard
Baidu TTS plugin for Flutter: online, offline and mixed speech synthesis on Android, iOS and HarmonyOS.
flutter_baidu_tts #
百度语音合成(TTS)的 Flutter 插件,支持在线 / 离线 / 混合(MIX)三种合成方式。
平台支持:
- Android:在线 / 离线 / 混合合成,支持
accessToken、apiKey + secretKey、iamKey三种鉴权方式。 - iOS:在线 / 离线 / 混合合成,支持
accessToken、apiKey + secretKey、iamKey鉴权。仅支持真机(SDK 静态库只有 arm64 设备切片,模拟器架构已在 podspec 中排除)。 - OHOS(HarmonyOS):在线 / 离线 / 混合合成,支持
accessToken与apiKey + secretKey鉴权。iamKey与offlineOverwriteAssets不适用,若传入会在initialize返回值的ignoredParams中列出。离线模型直接从resources/resfile/对应的context.resourceDir按路径加载,不做拷贝。
快速开始 #
final tts = FlutterBaiduTts();
// 事件流是广播流,订阅方自行 cancel
final sub = tts.typedEvents.listen((BaiduTtsEvent e) {
debugPrint('$e');
// 合成数据分片:e.event == 'SYNTHESIZE_DATA_ARRIVED',PCM 在 e.audioData
});
final init = await tts.initializeWithConfig(const BaiduTtsConfig(
apiKey: 'ak',
secretKey: 'sk',
));
if (init.isSuccess) {
await tts.speakText('你好,百度语音合成');
}
// 页面销毁时
await sub.cancel();
await tts.releaseTts();
错误处理约定 #
所有方法都以 {code, message, ...} 形式返回结果,失败时 code != 0,不抛
PlatformException,调用方需要检查 code(或使用 BaiduTtsResult.isSuccess)。
约定的负数码:
-1:一般错误(参数缺失、未初始化、SDK 抛异常等)-2:initialize正在进行中(并发调用)
其余非 0 值来自百度 SDK 的错误码(Android 为 getDetailCode(),iOS 为
NSError.code)。initialize 失败时返回值里还会带上 offlineCode /
offlineMessage(离线引擎加载结果)与 paramErrors(个别参数被 SDK 拒绝时的明细)。
需要更底层的原始 Map 返回值时,可直接使用 FlutterBaiduTtsPlatform.instance。
离线模型(接入方自备) #
离线模型(.dat,单个 8–16MB,全量约 56MB)是百度的专有授权文件,不随插件发布,
也不由插件重分发。离线合成需要接入方自行从
百度语音开放平台 获取模型,放进自己工程对应的原生资源
目录,再通过 offlineTextModelAsset / offlineSpeechModelAsset 用文件名引用(不是路径):
await tts.initializeWithConfig(BaiduTtsConfig(
apiKey: 'ak',
secretKey: 'sk',
appId: 'appId',
authSn: 'authSn',
enableOffline: true,
offlineTextModelAsset: 'bd_etts_common_text_txt_all_mand_eng_middle_big_v6.0.0_20240731.dat',
offlineSpeechModelAsset:
'bd_etts_common_speech_duxiaoyu_mand_eng_high_am-tac-csubgan16k_v4.9.0_20240918_20251031153737.dat',
));
三端放置目录一致约定如下(详见各端「接入」小节):
- Android:
android/app/src/main/assets/(插件首次initialize时拷贝到filesDir) - iOS:加入 Xcode 的 Runner target(进入
Bundle.main) - OHOS:
entry/src/main/resources/resfile/(解析为context.resourceDir,不拷贝)
也可以自行下载到磁盘后,用 offlineTextModelPath / offlineSpeechModelPath 传绝对路径,
优先级高于 asset 名。
Android 接入 #
插件的 manifest 声明 INTERNET 与 ACCESS_NETWORK_STATE(SDK 发请求前会查询网络
状态)。其余权限不会由插件代为声明,需要时请在宿主 App 自己的 manifest 中添加:
<!-- SDK 可用它生成更稳定的 cuid;Android 10+ 已无法获取 IMEI,可按需决定是否声明 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- 仅当离线模型放在应用沙箱之外时才需要 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
混淆规则已通过 consumerProguardFiles(android/consumer-rules.pro)随 AAR 下发,
宿主开启 minifyEnabled 时无需额外配置。
百度 Android SDK 以拆包形式内置在插件里:jar 在 android/libs/,.so 在
android/src/main/jniLibs/(arm64-v8a、armeabi-v7a、x86、x86_64)。因此接入方不需要
在自己的 build.gradle 里声明任何额外仓库,只依赖插件即可。
离线模型文件 #
插件不打包离线模型(单个模型 8–16MB,全量约 56MB,随插件下发会强加到每个接入方 的包体上)。离线合成需要接入方自行提供文本模型与音库模型:
- 放进宿主 App 的
android/app/src/main/assets/,通过offlineTextModelAsset/offlineSpeechModelAsset传文件名,插件会在首次initialize时拷贝到filesDir(offlineOverwriteAssets: true可强制覆盖); - 或自行下载到磁盘,通过
offlineTextModelPath/offlineSpeechModelPath传绝对路径。 路径不存在时initialize直接返回失败,不会静默回落。
示例工程用的模型放在 example/android/app/src/main/assets/,可作为参考。
离线合成同时还需要 appId 与 authSn。
iOS 接入 #
SDK 静态库 #
libBDSpeechTTSBaseKit.a 约 239MB,不纳入版本管理、也不随插件发布。pod install
阶段 podspec 会在缺失时自动从 Release 下载到 ios/Libs/(默认地址见 podspec 顶部,
可用环境变量 FLUTTER_BAIDU_TTS_IOS_LIB_URL 覆盖);下载失败或想手动接管时,也可自行从
百度 iOS TTS SDK 包(BDSpeechClientSDK_TTS)里把 BDSClientLib/libBDSpeechTTSBaseKit.a
放进 ios/Libs/。该库只有 arm64 设备切片,podspec 已通过
EXCLUDED_ARCHS[sdk=iphonesimulator*] 排除模拟器,iOS 侧只能在真机上运行。
离线模型文件 #
同样不随插件下发。offlineTextModelAsset / offlineSpeechModelAsset 传文件名时,
插件按以下顺序查找绝对路径:
offlineTextModelPath/offlineSpeechModelPath(显式绝对路径,优先级最高);Bundle.main——即把模型文件加入 Runner target 的 Resources(示例工程复用了example/android/app/src/main/assets/下的.dat,避免重复占用仓库体积);- 沙箱
Documents/——若自行下载模型到磁盘,可放这里再用绝对路径引用。
找不到、或 loadOfflineEngine 失败时 initialize 返回失败并带上 offlineCode /
offlineMessage,不会静默降级成在线。
音频会话由 SDK 自己管理(插件把 category 设为 playback),宿主如需自行接管
AVAudioSession,请在 initialize 之后再覆盖。
OHOS(HarmonyOS)接入 #
插件的鸿蒙实现以 HAR 形式提供,HAR 的 module.json5 不参与最终打包,其中声明的权限
不会合并进宿主应用,因此必须由接入方在自己的 entry(或对应 HAP/HSP)模块中声明联网
权限:
// entry/src/main/module.json5
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
}
]
}
}
未声明该权限时,TTS 初始化阶段的在线鉴权(PARAM_LICENSE_URL)会失败,导致合成不可用。
若测试模块(ohosTest)中也有需要联网的用例,需同样声明一份。
离线模型请放到 entry 模块的 resources/resfile/ 下,用
offlineTextModelAsset / offlineSpeechModelAsset 传相对文件名即可(会解析为
context.resourceDir 下的路径,不发生拷贝)。
与 Android / iOS 一致,插件本身不内置任何离线模型(模型单个 8–16MB,随插件下发会
超出 pub.dev 100MB 包体上限)。跑 OHOS 端的离线 example 时,需要自行把 .dat 模型拷进
example/ohos/entry/src/main/resources/resfile/(可复用
example/android/app/src/main/assets/ 下的同名文件)。
运行 example #
示例工程的鉴权信息集中在 example/lib/utils/tts_config.dart(TtsConfig)里,按平台
分成 Android / iOS / OHOS 三组。跑示例前请把其中的 apiKey / secretKey /
appId / authSn 换成自己在百度语音开放平台申请的凭据:
cd example
flutter run # Android
flutter run -d <真机> # iOS,模拟器不支持
注意:这些凭据目前是明文常量,仅用于本地跑通示例,不要把真实凭据提交到公开仓库。
已知限制 #
- iOS 静态库 239MB,超出 pub.dev 单包 100MB 上限,因此不随包发布,改为
pod install阶段自动下载(地址见 podspec,可用FLUTTER_BAIDU_TTS_IOS_LIB_URL覆盖)。 - iOS 仅支持真机(静态库无模拟器切片)。
- 升级原生 SDK 时需要同步核对其传递依赖:Android 侧拆包后没有依赖元数据,SDK 内部
用到的 OkHttp 在
android/build.gradle中显式声明。 - OHOS 离线鉴权的 license 地址目前固定为
https://upl.baidu.com/auth,不可配置。 - Android 侧未调用 SDK 的
loadAudioPlayer(),播放走 SDK 默认播放器。