news 2026/9/14 14:00:00

MNN TTS Android Demo 构建实战:从 NDK 环境配置到 CMake 原生库链接的全流程解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MNN TTS Android Demo 构建实战:从 NDK 环境配置到 CMake 原生库链接的全流程解析

MNN TTS Android Demo 构建实战:从 NDK 环境配置到 CMake 原生库链接的全流程解析

【免费下载链接】MNNMNN: A blazing-fast, lightweight inference engine battle-tested by Alibaba, powering high-performance on-device LLMs and Edge AI.项目地址: https://gitcode.com/GitHub_Trending/mn/MNN

本文基于 MNN 仓库中 MNN TTS Android Demo 构建文档 展开,完整覆盖 Demo 的工具链前置要求、Gradle/CMake 双层构建配置、MNN 核心库依赖链与安装运行验证方法。读完本文,你可以独立完成该 TTS 演示应用的编译、安装、启动与常见故障排查,并理解构建配置背后与源码的直接对应关系。

一、项目概述与模块结构

MNN TTS Android Demo 是基于 MNN(Mobile Neural Network)推理引擎的文本转语音(Text-to-Speech)演示应用,位于apps/frameworks/mnn_tts/目录下。它展示了如何在 Android 平台上调用 MNN TTS SDK 完成语音合成,当前内置了 BertVits2 与 Supertonic 两套 TTS 引擎实现(PIPER 为可选构建)。

整个mnn_tts模块由三部分构成:

mnn_tts/ ├── android/ # MNN TTS Android 库模块(Gradle library module) │ ├── build.gradle # 库模块构建配置 │ ├── java/ # Java/Kotlin 源代码 │ └── src/ │ └── main/java/com/alibaba/mnn/tts/ │ └── MNNTTS.kt # SDK 的 Kotlin 封装入口 ├── demo/android/ # Android Demo 应用 │ ├── build.gradle # 应用构建配置 │ ├── settings.gradle # Gradle 项目设置(挂载 :mnn_tts 模块) │ ├── src/main/ │ │ ├── java/ # Kotlin 源代码 │ │ └── res/ # Android 资源文件 │ └── build/ # 构建输出目录 ├── include/ # C++ 头文件(mnn_tts_sdk.hpp 等) ├── src/ # C++ 源代码实现 └── CMakeLists.txt # CMake 构建配置

两个 Gradle 模块之间通过 settings.gradle 完成装配:根工程名为MNNTTSDemo,其中include ':mnn_tts'一行将库模块的projectDir指向上级../../android目录,因此只需打开demo/android一个目录,即可同时构建库与应用:

rootProject.name = "MNNTTSDemo" include ':mnn_tts' project(':mnn_tts').projectDir = new File('../../android')

该文件同时通过pluginManagement统一声明了 AGP 与 Kotlin 插件版本(com.android.application/com.android.library均为 8.7.3,应用侧 Kotlin 插件为 1.9.22)。

二、前置要求:工具链版本与 MNN 核心库依赖

2.1 必需的工具与版本

以下版本信息来自构建文档,并与仓库中的 Gradle 配置逐一核对一致:

工具要求版本仓库中的依据
Android StudioArctic Fox 或更高构建文档推荐
Android SDKCompile SDK 35 / Min SDK 21(Android 5.0)/ Target SDK 35demo build.gradle 中compileSdk 35minSdk 21targetSdk 35
Android NDK27.2.12479018(推荐)库模块 build.gradle 中ndkVersion "27.2.12479018"
JDK17 或更高(Gradle 构建)构建文档要求
Gradle8.9(由 Wrapper 自动管理)gradle-wrapper.properties 中distributionUrl指向gradle-8.9-bin.zip
CMake3.22.1 或更高库模块 build.gradle 中version '3.22.1'

此外,gradle.properties 中开启了 AndroidX、Jetifier 与nonTransitiveRClass,并将 Gradle JVM 堆内存设为 2048m。

2.2 依赖预编译的 MNN 核心库

该 Demo 的 C++ 层并非从零编译 MNN,而是链接一份预编译的libMNN.so。这一点在 CMakeLists.txt 中有明确体现:

set(MNN_SOURCE_ROOT ${CMAKE_CURRENT_LIST_DIR}/../../../) set(MNN_INSTALL_ROOT "${MNN_SOURCE_ROOT}/project/android/build_64") set(LIB_PATH "${MNN_INSTALL_ROOT}/lib") set(MNN_EXPRESS_PATH "${LIB_PATH}/libMNN_Express.so") add_library(MNN SHARED IMPORTED) set_target_properties(MNN PROPERTIES IMPORTED_LOCATION "${LIB_PATH}/libMNN.so")

从源码结构看,MNN_SOURCE_ROOTapps/frameworks/mnn_tts/向上回溯三层定位到仓库根目录,因此 MNN 库的期望位置为仓库内的project/android/build_64/lib/libMNN.so(构建文档中写作作者本机的绝对路径,实际均以仓库根目录为准)。如果该库不存在,需要先执行仓库提供的 Android 构建脚本:

cd project/android ./build_64.sh

另外两处值得注意的实现细节:

  1. 可选的libMNN_Express.so:CMake 会检查build_64/lib/libMNN_Express.so是否存在,若存在则一并声明为MNNExpress导入目标并链接(注释为 "legacy split runtime"),不存在时自动降级为只链接libMNN.so
  2. Android 专属链接选项BUILD_ANDROID开启时会追加-Wl,-z,max-page-size=16384链接选项,用于适配 16KB 内存页大小的 Android 设备。

BUILD_ANDROID标志无需手动指定,CMake 在检测到ANDROID平台变量后会自动强制置为 ON:

option(BUILD_ANDROID "Build for Android" OFF) if(ANDROID) set(BUILD_ANDROID ON CACHE BOOL "Build for Android" FORCE) endif()

三、构建步骤

3.1 方法一:Gradle 命令行(推荐)

apps/frameworks/mnn_tts/demo/android目录下依次执行:

cd apps/frameworks/mnn_tts/demo/android # 1. 清理之前的构建(可选) ./gradlew clean # 2. 构建 Debug APK ./gradlew assembleDebug # 3. 构建 Release APK ./gradlew assembleRelease # 4. 查看构建输出 ls -lh build/outputs/apk/debug/

生成的 APK 文件:

  • Debugbuild/outputs/apk/debug/MNNTTSDemo-arm64-v8a-debug.apk(约 15 MB)
  • Releasebuild/outputs/apk/release/MNNTTSDemo-arm64-v8a-release-unsigned.apk(约 8 MB)

QUICKREF.md 中给出了构建耗时的参考:Clean 约 5 秒、首次构建约 2~3 分钟、增量构建约 30~60 秒、安装到设备约 10 秒。

一个实操细节:当前仓库的 demo build.gradle 在preBuild之前挂接了一个downloadAndUnzipNativeLibs任务,当src/main/jniLibs/arm64-v8a/中缺少libsherpa-mnn-jni.so时,会从 CDN 自动下载并解压 arm64-v8a 原生库包,因此首次构建需要网络可用。

3.2 方法二:Android Studio

  1. 打开项目:选择 "Open an Existing Project",导航到apps/frameworks/mnn_tts/demo/android目录并确认;
  2. Gradle 同步:Android Studio 会自动开始同步;若未触发,点击 "File" → "Sync Project with Gradle Files";
  3. 配置构建变体:在左下角 "Build Variants" 中选择debugrelease
  4. 构建 APK:点击 "Build" → "Build Bundle(s) / APK(s)" → "Build APK(s)",或使用快捷键 Ctrl+Shift+A(Windows/Linux)/ Cmd+Shift+A(Mac);
  5. 查看构建结果:构建成功后点击通知中的 "locate" 查看 APK 位置。

四、构建配置详解

4.1 应用配置(demo/android/build.gradle)

应用 build.gradle 的关键配置:

android { namespace 'com.alibaba.mnn.tts.demo' compileSdk 35 // 编译 SDK 版本 defaultConfig { applicationId "com.alibaba.mnn.tts.demo" minSdk 21 // 最低支持 Android 5.0 targetSdk 35 // 目标 SDK versionCode 1 // 应用版本号 versionName "1.0" // 应用版本名称 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } splits { abi { enable true reset() include 'arm64-v8a' // 仅构建 ARM64 版本 universalApk false // 不生成通用 APK } } }

依赖清单与构建文档一致(Kotlin 侧依赖 androidx 基础组件 + 协程):

dependencies { implementation project(':mnn_tts') // MNN TTS 库 implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'com.google.android.material:material:1.10.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.7.0' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3' implementation 'androidx.core:core-ktx:1.16.0' implementation 'androidx.recyclerview:recyclerview:1.3.2' implementation 'androidx.cardview:cardview:1.0.0' }

4.2 库模块配置(android/build.gradle)

库模块 build.gradle 是原生代码构建的核心,实际配置比构建文档摘录的更完整:

android { namespace 'com.alibaba.mnn.tts' compileSdk 34 ndkVersion "27.2.12479018" // NDK 版本 sourceSets { main.java.srcDirs += ['java'] } defaultConfig { minSdk 21 targetSdk 35 externalNativeBuild { cmake { cppFlags "-std=c++17" arguments "-DANDROID_STL=c++_shared", "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON" } } ndk { abiFilters 'arm64-v8a' } } externalNativeBuild { cmake { path file('../CMakeLists.txt') // 指向 mnn_tts/CMakeLists.txt version '3.22.1' } } buildFeatures { buildConfig true prefab true } prefab { mnn_tts { headers "include/mnn_tts" } } }

几个配置项的含义:

  • cppFlags "-std=c++17":与 CMake 中CMAKE_CXX_STANDARD 17保持一致;
  • -DANDROID_STL=c++_shared:使用动态 C++ 标准库,即最终 APK 中携带的libc++_shared.so
  • -DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON:与 CMake 侧的 16KB 页对齐选项配合,支持新的内存页大小;
  • abiFilters 'arm64-v8a':原生代码同样只编译 ARM64;
  • prefab配置将include/mnn_tts下的头文件(如 common.h)暴露给消费方模块。

4.3 CMake 配置选项(CMakeLists.txt)

mnn_tts/CMakeLists.txt 定义了四个关键选项:

选项默认值说明
BUILD_BERTVITS2ON构建 BertVits2 TTS 引擎(中文/英文 G2P、Bert 音素预测、声学模型生成)
BUILD_PIPEROFF构建 PIPER TTS 引擎(依赖 espeak-ng 子模块,默认不启用)
BUILD_SUPERTONICON构建 Supertonic TTS 引擎
BUILD_ANDROIDOFF(自动检测)Android 平台标志,检测到ANDROID变量后强制置 ON

各选项直接决定编译哪些源文件并追加哪些头文件目录。例如BUILD_BERTVITS2开启时纳入src/bertvits2/下共 11 个源文件(text_preprocessor、chinese_g2p、english_bert、tts_generator 等);BUILD_ANDROID开启时额外纳入src/android/tts_service.cppsrc/android/tts_service_jni.cpp两个 JNI 服务源文件——这正是 Android 平台上 TTS 引擎服务的原生实现入口。

最终产物为动态库libmnn_tts.soadd_library(${PROJECT_NAME} SHARED ...)),链接logMNN(Android 平台另链接系统 log 库),形成如下原生库组合:

  • libMNN.so:MNN 核心推理引擎(来自project/android/build_64预构建产物);
  • libmnn_tts.so:MNN TTS SDK 实现(由本 CMake 工程构建);
  • libc++_shared.so:C++ 标准库(c++_sharedSTL 模式)。

五、安装、运行与验证

5.1 安装到设备

# 方式一:Gradle 命令 ./gradlew installDebug # 方式二:adb 命令 adb install build/outputs/apk/debug/MNNTTSDemo-arm64-v8a-debug.apk # 方式三:Android Studio 工具栏 "Run" 按钮,选择目标设备后自动安装并启动

5.2 启动应用

# 启动 Demo 主界面 adb shell am start -n com.alibaba.mnn.tts.demo/.MainActivity # 停止 / 卸载 / 清数据(来自 QUICKREF.md 的常用命令) adb shell am force-stop com.alibaba.mnn.tts.demo adb uninstall com.alibaba.mnn.tts.demo adb shell pm clear com.alibaba.mnn.tts.demo

从 AndroidManifest.xml 可以看到,这个 Demo 除了普通 Launcher 应用之外还有一个值得注意的身份:它声明了一个com.mnn.tts.demo.MnnTtsService服务并匹配android.intent.action.TTS_SERVICE意图,附带@xml/tts_engine元数据——也就是说它同时注册为系统 TTS 引擎,用户可以在系统"设置 → 语言和输入法 → 文字转语音"中选择 "MNN TTS Engine",配套的设置界面由MnnTtsSettingsActivity(匹配TTS_SERVICE_SETTINGS意图)提供。应用还申请了RECORD_AUDIOMODIFY_AUDIO_SETTINGS等权限,并通过<queries>声明了对 TTS 服务意图的可见性。

5.3 日志与性能分析

# 查看应用日志 adb logcat -s MNN_TTS:* AndroidRuntime:E # 查看原生日志 adb logcat -s DEBUG:* native:*

性能侧可使用 Android Studio 的 Profiler(View → Tool Windows → Profiler)监控 CPU/内存,或使用 Systrace 抓取系统级调度轨迹(python systrace.py -t 10 -o trace.html sched freq idle)。

六、常见问题与解决方案

以下五项 FAQ 均继承自构建文档,并补充了仓库内可核对的路径:

1. NDK 未找到(NDK not configured)

local.properties中配置 NDK 与 SDK 路径(以本机实际路径替换):

echo "ndk.dir=/path/to/sdk/ndk/27.2.12479018" >> local.properties echo "sdk.dir=/path/to/sdk" >> local.properties

2. MNN 库未找到(libMNN.so not found)

先构建 MNN 核心库(对应 CMakeLists.txt 中MNN_INSTALL_ROOT指向的位置):

cd project/android ./build_64.sh ls project/android/build_64/lib/libMNN.so # 验证产物存在

3. Gradle 同步失败

清理缓存并强制刷新依赖:

./gradlew clean rm -rf .gradle build ./gradlew build --refresh-dependencies

4. CMake 构建失败

按顺序检查:NDK 版本是否为 27.2.12479018、CMake 版本是否 ≥ 3.22.1、project/android/build_64/lib/libMNN.so是否存在。可用./gradlew assembleDebug --info查看详细构建日志。

5. ABI 不匹配(INSTALL_FAILED_NO_MATCHING_ABIS)

应用仅支持 ARM64(arm64-v8a)设备,需确保测试设备为 ARM64 架构,或修改build.gradlesplits.abindk.abiFilters添加其他 ABI 支持。

七、性能优化建议

Release 构建优化

构建文档建议的 Release 优化开关(当前 demo build.gradle 中minifyEnabled默认为false,以下为发布时的可选增强):

buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt') shrinkResources true } }

Release 构建同时会自动使用优化后的原生库编译选项。

运行时优化

  1. 模型加载:首次加载 TTS 模型耗时较长,建议走异步加载路径(Demo 中使用 Kotlin 协程封装);
  2. 内存管理:及时释放不再使用的模型资源;
  3. 线程池:使用合理的线程数量进行推理。

八、运行时架构

MainActivity.kt ├── ModelAdapter.kt # 模型列表适配器 ├── AudioChunksPlayer.kt # 分块音频播放器(实时播放合成音频) └── MNN TTS SDK (libmnn_tts.so) ├── BertVits2 TTS # BertVits2 语音合成(src/bertvits2/) ├── Supertonic TTS # Supertonic 语音合成(src/supertonic/) └── MNN Engine # MNN 推理引擎(libMNN.so)

对应的源码目录与 include/ 下的公开头文件一一对应:BertVits2 引擎的对外实现头为 mnn_bertvits2_tts_impl.hpp,Supertonic 引擎为 mnn_supertonic_tts_impl.hpp,SDK 统一入口为 mnn_tts_sdk.hpp。

关键功能:

  1. 文本转语音:输入文本,经 G2P/文本前端处理后由声学模型生成语音;
  2. 模型管理:支持多种 TTS 模型切换(Demo 中由ModelConfig/ModelAdapter管理);
  3. 音频播放AudioChunksPlayer分块播放生成的语音,实现低延迟实时收听;
  4. 性能监控:显示推理时间和资源使用;
  5. 系统 TTS 引擎注册:通过MnnTtsService接入 Android 系统 TTS 框架(见第五节清单分析)。

九、版本信息与适用前提

  • 应用版本:1.0(versionCode 1)
  • 最低 Android 版本:5.0(API 21)
  • 目标 Android 版本:14.0(API 35)
  • 支持的架构:ARM64(arm64-v8a)
  • 许可证:遵循 MNN 项目许可证条款

适用前提说明:本文所有构建步骤均以当前仓库状态为准,MNN 核心库必须由仓库内的 build_64.sh 先行产出;构建文档中出现的作者本机绝对路径(如/Users/...)在仓库内均应理解为相对仓库根目录的路径。配套的快速开始与常用命令速查可参考同目录的 README.md 和 QUICKREF.md。

【免费下载链接】MNNMNN: A blazing-fast, lightweight inference engine battle-tested by Alibaba, powering high-performance on-device LLMs and Edge AI.项目地址: https://gitcode.com/GitHub_Trending/mn/MNN

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 13:59:33

零基础自学AI大模型:系统学习路线指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/14 13:56:11

ToolJet 如何在 RunJS 中故意抛出错误来调试查询失败事件处理?

ToolJet 如何在 RunJS 中故意抛出错误来调试查询失败事件处理&#xff1f; 【免费下载链接】ToolJet Open-source foundation of ToolJet AI - the enterprise app generation platform for internal tools, dashboards, business applications, workflows and AI agents. Buil…

作者头像 李华
网站建设 2026/9/14 13:55:49

Keyme Pass通过坚果云WebDAV实现安全自动同步

1. 项目背景与核心需求 作为一名长期使用密码管理工具的老用户&#xff0c;我一直在寻找一种安全可靠的自动同步方案。Keyme Pass&#xff08;KeePass兼容客户端&#xff09;作为开源密码管理工具&#xff0c;其数据库文件通常需要手动复制到不同设备&#xff0c;这种操作既繁琐…

作者头像 李华
网站建设 2026/9/14 13:55:47

SSD/U盘数据恢复核心技术解析与实战指南

1. 项目概述&#xff1a;免费数据恢复工具的核心价值去年帮朋友抢救一块突然罢工的固态硬盘时&#xff0c;我试遍了市面上十几款数据恢复软件。大多数免费工具要么对SSD支持有限&#xff0c;要么预览功能形同虚设——直到发现这款支持固态硬盘/U盘类型预览的免费方案。不同于传…

作者头像 李华
网站建设 2026/9/14 13:55:22

三阶RC模型下的无迹卡尔曼滤波电池SOC估算实践

简介&#xff1a;面向锂电池SOC估算与BMS算法开发的MATLAB/Simulink资源包&#xff0c;适合从事电池状态估计研究的工程师与学生。内容覆盖改进扩展卡尔曼滤波&#xff08;EKF&#xff09;估算SOC、基于卡尔曼滤波的电池参数辨识、三阶RC等效电路模型&#xff0c;以及无迹卡尔曼…

作者头像 李华