Tauri Android 打包原理与实战指南
基于 JoyaLand 项目的实际打包经验整理,记录原理、流程与踩坑解决方案。
一、Tauri Android 打包架构原理
1.1 整体架构
┌─────────────────────────────────────────────┐
│ JoyaLand Android App │
├──────────────────┬──────────────────────────┤
│ 前端层 (WebView) │ 原生层 (Rust/JNI) │
│ ┌────────────┐ │ ┌────────────────────┐ │
│ │ HTML/CSS │ │ │ tauri-android │ │
│ │ JavaScript │◄─┼─►│ (Kotlin/Java) │ │
│ │ Canvas 2D │ │ ├────────────────────┤ │
│ └────────────┘ │ │ libapp_lib.so │ │
│ │ │ (Rust 编译产物) │ │
└──────────────────┴──────────────────────────┘
▲
│ Vite 构建的静态资源
│ (dist/ 目录)
Tauri Android 的核心思路:
- 前端:使用系统 WebView 渲染 HTML/JS/CSS(无需打包 Chromium)
- 后端:Rust 代码编译为
.so动态库,通过 JNI 被 Kotlin/Java 调用 - 桥接:Tauri 的 IPC 机制连接前后端(命令调用、事件通知)
1.2 构建工具链
Vite (前端构建)
↓ 生成 dist/
Cargo (Rust 编译)
↓ 交叉编译 4 个 ABI 的 .so 文件
Gradle (Android 构建)
↓ 打包 APK/AAB
apksigner (APK 签名)
↓
最终 APK
1.3 支持的 Android ABI
| ABI | Rust Target | 对应设备 |
|---|---|---|
| arm64-v8a | aarch64-linux-android | 现代 64 位 ARM 手机(主流) |
| armeabi-v7a | armv7-linux-androideabi | 旧款 32 位 ARM 手机 |
| x86 | i686-linux-android | 模拟器(32 位) |
| x86_64 | x86_64-linux-android | 模拟器(64 位)/ 部分平板 |
二、环境准备
2.1 必要工具
| 工具 | 作用 | 安装来源 |
|---|---|---|
| Rust + Cargo | 编译原生代码 | rustup.rs |
| Android SDK | Android 构建工具 | Android Studio / 命令行 |
| Android NDK | 交叉编译工具链 | SDK Manager |
| JDK 8+ | Gradle 运行环境 | Oracle / OpenJDK |
| Gradle | Android 构建系统 | gradle.org 或系统安装 |
| Node.js + npm | 前端依赖管理 | nodejs.org |
2.2 Rust Android 编译目标
rustup target add aarch64-linux-android
rustup target add armv7-linux-androideabi
rustup target add i686-linux-android
rustup target add x86_64-linux-android
2.3 环境变量
# Windows PowerShell
$env:ANDROID_HOME = "D:\Android\Sdk"
$env:PATH += ";D:\Android\Sdk\platform-tools"
三、打包完整流程
3.1 初始化 Android 项目
npx tauri android init
执行后会:
- 检测
ANDROID_HOME环境变量,找到 SDK 路径 - 自动检测并使用已安装的 NDK(如
D:\Android\Sdk\ndk\29.0.x) - 安装 4 个 Android Rust 编译目标(如未安装)
- 在
src-tauri/gen/android/生成 Android Gradle 项目
生成的目录结构:
src-tauri/gen/android/
├── app/
│ ├── build.gradle.kts
│ ├── src/main/
│ │ ├── java/com/liupe/joyaland/generated/ ← Tauri 自动生成的 Kotlin 桥接代码
│ │ └── jniLibs/ ← 编译好的 .so 文件(symlink)
│ └── proguard-rules.pro
├── buildSrc/ ← 包含自定义 BuildTask(调用 Cargo)
├── gradle/wrapper/
│ └── gradle-wrapper.properties ← Gradle 版本配置
├── gradlew.bat ← Gradle Wrapper 启动脚本
└── settings.gradle
3.2 构建 APK
$env:ANDROID_HOME = "D:\Android\Sdk"
npx tauri android build --apk
构建过程分为以下阶段:
阶段 1:前端构建
npm run build → Vite → dist/
- 执行
tauri.conf.json中配置的beforeBuildCommand - 生成静态资源到
dist/目录
阶段 2:Rust 交叉编译(最耗时)
Cargo → 4 个 .so 文件
- 为每个 ABI 分别运行
cargo build --release --target <abi> - 使用 NDK 中的交叉编译工具链(如
aarch64-linux-android24-clang) - 首次编译需要 20-60 分钟,后续增量编译 1-5 分钟
编译产物位置:
src-tauri/target/aarch64-linux-android/release/libapp_lib.so
src-tauri/target/armv7-linux-androideabi/release/libapp_lib.so
src-tauri/target/i686-linux-android/release/libapp_lib.so
src-tauri/target/x86_64-linux-android/release/libapp_lib.so
阶段 3:Gradle 打包
gradlew assembleUniversalRelease → APK
- Gradle 调用
buildSrc中的BuildTask触发各 ABI 的 Rust 编译 - Kotlin 代码编译(Tauri 桥接层)
- 资源合并、R8 代码压缩混淆
- 打包为 APK
输出位置:
src-tauri/gen/android/app/build/outputs/apk/universal/release/
app-universal-release-unsigned.apk
阶段 4:APK 签名
# 1. 生成签名密钥(只需一次)
keytool -genkey -v -keystore joyaland-release.keystore `
-alias joyaland -keyalg RSA -keysize 2048 -validity 10000 `
-storepass <密码> -keypass <密码> `
-dname "CN=JoyaLand, OU=Dev, O=liupe, L=Beijing, S=Beijing, C=CN"
# 2. 签名 APK
apksigner sign --ks joyaland-release.keystore `
--ks-key-alias joyaland `
--ks-pass pass:<密码> --key-pass pass:<密码> `
--out JoyaLand-v1.0.0.apk `
app-universal-release-unsigned.apk
⚠️ 重要:
joyaland-release.keystore文件必须妥善保管。发布到应用商店后,更新版本必须使用同一密钥签名,否则无法覆盖安装。
四、实际遇到的问题与解决方案
问题 1:ANDROID_HOME 未设置导致初始化失败
现象:
Error: ANDROID_HOME is not set
或自动探测到错误路径(C:\Users\xxx\AppData\Local\Android\Sdk),与实际使用的 SDK 路径不符。
原因:
- 系统环境变量未配置,或配置了不同路径的 SDK
- Tauri 会自动探测系统默认路径,不一定是用户实际使用的路径
解决方案:
# 每次打包前手动设置(临时)
$env:ANDROID_HOME = "D:\Android\Sdk"
# 或永久设置系统环境变量(推荐)
[System.Environment]::SetEnvironmentVariable("ANDROID_HOME", "D:\Android\Sdk", "User")
问题 2:Rust target 下载失败(文件重命名错误)
现象:
error: component download failed for rust-std-i686-linux-android:
could not rename downloaded file from '...partial' to '...':
系统找不到指定的文件。(os error 2)
原因:
- 文件已存在于缓存中,但 rustup 下载流程中遇到并发/临时文件问题
- 实际上 target 已经安装成功,只是报了错误
解决方案:
# 验证是否实际已安装
rustup target list --installed
# 如果列表中有目标,则忽略错误继续即可
问题 3:Gradle 网络超时(无法下载 gradle-8.14.3-bin.zip)
现象:
Downloading https://services.gradle.org/distributions/gradle-8.14.3-bin.zip
Exception in thread "main" java.io.IOException: ... failed: timeout
原因:
- 国内网络无法访问
services.gradle.org gradle-wrapper.properties配置的是从网络下载 Gradle
解决方案:直接修改 gradlew.bat,绕过 Wrapper,调用本地已安装的 Gradle
修改 src-tauri/gen/android/gradlew.bat:
@if "%DEBUG%" == "" @echo off
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem 直接使用本地安装的 Gradle,跳过网络下载
set GRADLE_CMD=D:\tool\gradle-8.14\bin\gradle.bat
if not exist "%GRADLE_CMD%" (
echo ERROR: Gradle not found at %GRADLE_CMD%
exit /b 1
)
"%GRADLE_CMD%" %*
:end
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
问题 4:Kotlin 增量编译失败(不同盘符路径冲突)
现象:
java.lang.IllegalArgumentException: this and base files have different roots:
C:\Users\xxx\.cargo\registry\...\tauri-2.10.3\...\ActivityCallback.kt
and E:\WeChatProjects\JoyaLand\src-tauri\gen\android
原因:
- Kotlin 增量编译器要求所有源文件在同一个根路径下
- Tauri 的 Kotlin 源文件在 C 盘(Cargo 注册表),项目在 E 盘,跨盘符导致相对路径计算失败
解决方案:
- 此错误会自动 fallback 到非增量编译模式(
Using fallback strategy: Compile without Kotlin daemon) - 不影响最终 APK 生成,可以忽略
若要根本解决,可将整个项目放在与 Cargo 注册表相同的盘符下(如 C 盘)。
问题 5:Gradle 版本不匹配
现象:
- 本地安装 Gradle 8.14,但
gradle-wrapper.properties要求 8.14.3 - 直接用
gradlew会下载 8.14.3,网络超时失败
解决方案:
- 直接修改
gradlew.bat调用本地 Gradle 8.14(见问题 3 的解决方案) - Gradle 8.14 与 8.14.3 兼容,实际构建无影响
问题 6:JDK 版本过高导致警告
现象:
Kotlin does not yet support 24 JDK target, falling back to Kotlin JVM_22 JVM target
Java compiler version 24 has deprecated support for compiling with source/target version 8.
原因:
- 系统 JDK 版本为 24,Kotlin 最高支持 JVM 22 目标
- Android 项目的
sourceCompatibility设置为 Java 8,JDK 24 已弃用此设置
影响:仅为警告,不影响 APK 构建,可正常使用。
根本解决(可选):安装 JDK 17 或 JDK 21 并配置 JAVA_HOME。
问题 7:APK 为未签名版本,无法安装
现象:
- 构建完成后的 APK 文件名为
app-universal-release-unsigned.apk - 直接安装到手机报错
解决方案:使用 apksigner 工具签名(见第三节阶段 4)
五、关键配置文件说明
tauri.conf.json(部分)
{
"build": {
"frontendDist": "../dist",
"devUrl": "http://localhost:1420",
"beforeDevCommand": "npm run dev",
"beforeBuildCommand": "npm run build"
},
"app": {
"windows": [{
"width": 450,
"height": 950,
"resizable": false,
"center": true
}]
}
}
gradle-wrapper.properties
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
在网络受限环境下,此文件的
distributionUrl会导致超时。已通过修改gradlew.bat绕过。
六、常用命令速查
# 设置 Android SDK 路径(每次打包前执行)
$env:ANDROID_HOME = "D:\Android\Sdk"
# 初始化 Android 项目(只需一次)
npx tauri android init
# 构建 APK
npx tauri android build --apk
# 构建 debug APK(开发调试用)
npx tauri android build --apk --debug
# 签名 APK
$buildTools = "D:\Android\Sdk\build-tools\36.1.0"
& "$buildTools\apksigner.bat" sign `
--ks joyaland-release.keystore `
--ks-key-alias joyaland `
--ks-pass pass:joyaland123 `
--key-pass pass:joyaland123 `
--out JoyaLand-v1.0.0.apk `
app-universal-release-unsigned.apk
# 验证签名
& "$buildTools\apksigner.bat" verify --verbose JoyaLand-v1.0.0.apk
# 通过 ADB 安装到已连接设备
adb install JoyaLand-v1.0.0.apk
七、首次 vs 增量构建时间对比
| 构建类型 | 前端构建 | Rust 编译 | Gradle 打包 | 总计 |
|---|---|---|---|---|
| 首次构建 | ~1 秒 | ~20-60 分钟 | ~5-10 分钟 | ~30-70 分钟 |
| 增量构建(无 Rust 变更) | ~1 秒 | ~1-2 分钟 | ~2-3 分钟 | ~3-5 分钟 |
| 增量构建(有 Rust 变更) | ~1 秒 | ~3-10 分钟 | ~2-3 分钟 | ~5-15 分钟 |
Rust 编译缓存保存在
src-tauri/target/目录,体积较大(数 GB),请勿随意删除。
八、输出文件位置
| 文件 | 路径 |
|---|---|
| 未签名 APK | src-tauri/gen/android/app/build/outputs/apk/universal/release/app-universal-release-unsigned.apk |
| 已签名 APK | JoyaLand-v1.0.0.apk(项目根目录) |
| 签名密钥 | joyaland-release.keystore(项目根目录,请备份) |
| Rust 编译缓存 | src-tauri/target/ |
| Android 项目 | src-tauri/gen/android/ |