解释Unity原生TTS的离线限制

解读

面试官问“Unity原生TTS的离线限制”,并不是想听你背文档,而是考察三点:

  1. 是否真正在国内商用环境踩过坑;
  2. 能否把“Unity-引擎层”与“平台-系统层”的权责边界说清楚;
  3. 面对限制,有没有工程化兜底方案(热更、插件、云端)。
    回答时务必把“离线”二字咬死:无网、弱网、合规审核、包体大小、HarmonyOS 与 Android 10+ 权限变更都要点到。

知识点

  1. Unity 引擎本身不带语音合成核心,所谓“原生”只是对 Windows SAPI、Android TTS、iOS AVSpeechSynthesizer、macOS NSSpeechSynthesizer 的 C# 桥接。
  2. 离线限制分四层
    系统层:Android 8 以下默认引擎“Pico TTS”中文音色缺失;HarmonyOS 2 以后不再预装Google TTS,厂商可裁剪;iOS 15+ 离线音色需用户手动下载(设置→辅助功能→语音内容→声音→下载),首次使用弹窗大小 100~200 MB,App 无法静默触发
    权限层:Android 11+ 对 /sdcard/Android/data/<pkg>/files/tts 目录限制分区存储,离线语音包无法通过 Unity 的 Application.persistentDataPath 直接解压;iOS 的 AVSpeechSynthesisVoice 在离线场景下若用户未下载,系统会强制回退到当前系统语言音色,不会抛异常,导致中文读出英文口音。
    包体层:Unity 打包时不会把系统 TTS 引擎打进 APK/IPA,国内渠道(华为、OPPO、小米)审核要求总包 ≤ 150 MB,若自带第三方离线合成 SDK(讯飞、百度)极易超限。
    合规层:工信部 337 号文要求任何语音库必须内置敏感词过滤模块,系统自带离线音色不含该功能,商用上架会被驳回。
  3. Unity 侧 API 限制:SpeechSynthesizer.GetInstalledVoices() 在 Android 返回列表受 系统设置→语言与输入法→文字转语音输出→引擎 控制,无网络时无法动态增删SpeechSynthesizer.Speak() 在 WebGL 平台直接抛 PlatformNotSupportedException
  4. 性能陷阱:Android 10+ 的 “后台启动前台服务” 限制导致在 Unity 退后台调用 TTS 可能被系统静音;iOS 的 AVAudioSession 类别若为 Ambient,锁屏后会中断合成,需要手动切换为 Playback 并加 Background Mode:audio,但审核可能被拒。

答案

Unity 的“原生 TTS”只是对宿主平台 API 的薄封装,离线场景下存在四类硬伤

  1. 音色不可保证:Android 8 以下与 HarmonyOS 大多无中文离线包,iOS 需用户手动下载;若未就绪,系统会静默回退到英文或系统默认音,App 无法感知。
  2. 包体与合规:Unity 无法把系统引擎打包,自带第三方离线 SDK 又会让 APK 超过国内渠道150 MB 红线,且系统音色不含敏感词过滤过审风险高
  3. 权限与存储:Android 11+ 分区存储限制,离线语音包无法通过 Unity 自动解压到公共目录;iOS 首次下载必须弹系统设置,不能静默完成,弱网体验差。
  4. 平台差异:WebGL 完全不支持;Android 退后台调用会被系统静音;iOS 锁屏后需改 AVAudioSession 类别,否则中断合成,但改类别可能触发审核问题。
    因此,Unity 原生 TTS 只能做 Demo 或联网场景,正式产品需插件化兜底:接入讯飞、百度离线合成,通过 AssetBundle 按需下载语音库,同时内置敏感词过滤表,才能在国内市场真正跑通离线需求。

拓展思考

  1. 若项目要求零权限、零流量,可把 2000 句常用中文语音提前录成 8 kHz Ogg Vorbis,用 Addressables 按首字母分包,运行时拼接,包体可压到 30 MB 以内,完全避开 TTS 限制。
  2. 对于数字人唇形同步,离线 TTS 需输出 PCM 实时流音素时间戳,Unity 原生 API 不提供;可用 Android JNI 直接调 SynthesisCallback 或 iOS AVSpeechSynthesizerDelegate,把音素回调回传 Unity,再驱动 BlendShape,实现离线唇同步。
  3. HarmonyOS Next 原生环境,系统 TTS 接口改为 @ohos.tts,Unity 2022 LTS 尚未适配,需自己写 AndroidJavaProxy 桥接 arkts 层,否则离线调用直接失效,这是明年国内项目必须提前踩的坑。