📱 在手机上编译安卓应用?我踩过的那些坑,都在这里了
没有电脑也能写 Android App?在手机 Termux 环境里,我把一个多模块 + Flutter 的项目完整编译出了 APK。这篇文章记录全部流程与踩坑经验。
一、为什么要在手机上编译安卓应用?
也许你觉得奇怪:手机性能再强,也不如电脑方便。但真实场景确实存在:
- 出差在外,只有一台手机,临时要改个 App 打包
- 学习验证,想快速跑通 Android 构建流程,又不想背电脑
- 嵌入式/特殊环境,比如树莓派(ARM 架构)上跑 CI
而手机上的 Termux(Android 的 Linux 终端模拟器)+ proot(免 root 的 Linux 沙箱),就能搭建一套完整的安卓编译环境。
但真正的坑,才刚刚开始……
二、环境搭建:Termux + proot + Alpine
手机 (Android 11+)
└── Omnibot App(内置 proot 沙箱)
└── Alpine Linux (aarch64)
├── JDK 17
├── Android SDK + Build-Tools
├── Gradle
└── (可选)Flutter SDK表面上看一切就绪,但当你好不容易把项目拉下来,执行:
./gradlew assembleDebug迎接你的不是 BUILD SUCCESSFUL,而是一连串的:
qemu-x86_64: Could not open '/lib64/ld-linux-x86-64.so.2'为什么?
三、核心坑点:x86_64 与 aarch64 的"错位"
Google 官方发布的 Android SDK 工具,几乎全是 x86_64 架构的:
| 工具 | 官方版本 | 问题 |
|---|---|---|
aapt2(资源编译器) | x86_64 | ARM 上无法直接运行 |
aidl(接口编译器) | x86_64 | 同上 |
zipalign(对齐工具) | x86_64 | 同上 |
NDK(原生开发套件) | x86_64 | 整个工具链都用不了 |
cmake | x86_64 | Flutter/NDK 构建必用 |
而手机是 aarch64(ARM64) 架构。没有 binfmt_misc,proot 里也跑不了 x86_64 二进制。
💡 换个说法:你在 ARM 的厨房里,拿到了一整套只有 x86 接口的电器,全都没法插电。
解决方案的钥匙,藏在 GitHub 上一个宝藏仓库:lzhiyong/termux-ndk。
四、解决一:用 termux-ndk 装 ARM64 NDK
lzhiyong/termux-ndk 专门为 Termux 编译了 aarch64 架构的 NDK,所有工具链(clang、lld、ndk-build)都是 ARM 原生可执行的。
# 下载 aarch64 NDK(约 330MB)
curl -L -o ndk.7z \
https://github.com/lzhiyong/termux-ndk/releases/download/android-ndk/android-ndk-r29-aarch64.7z
# 解压
7z x ndk.7z -o/opt/android-sdk/ndk/
# 目录名改成项目要求的 NDK 版本
mv /opt/android-sdk/ndk/android-ndk-r29 /opt/android-sdk/ndk/28.2.13676358
# 伪装版本号(实际是 r29,功能向下兼容)
cat > /opt/android-sdk/ndk/28.2.13676358/source.properties << EOF
Pkg.Desc = Android NDK
Pkg.Revision = 28.2.13676358
EOF验证一下:
/opt/android-sdk/ndk/28.2.13676358/toolchains/llvm/prebuilt/linux-x86_64/bin/clang --version
# 输出:
# Android clang version 21.0.0
# Target: aarch64-unknown-linux-musl ← 原生 ARM 可执行!✅ 关键点:NDK 里的工具链目录名叫 linux-x86_64 是历史遗留,二进制实际是 aarch64 的,能直接跑。五、解决二:ARM64 build-tools(aapt2/aidl/zipalign)
同一个仓库还发布了 android-sdk-aarch64.7z(约 290MB),里面有 ARM64 版的完整 SDK 工具:
7z x android-sdk-aarch64.7z "android-sdk/build-tools/35.0.0/*"
# 用 ARM64 版替换 x86_64 版
cp android-sdk/build-tools/35.0.0/{aapt2,aidl,zipalign} \
/opt/android-sdk/build-tools/35.0.0/替换后:
/opt/android-sdk/build-tools/35.0.0/aapt2 version
# Android Asset Packaging Tool (aapt) 2.19-B.1cc93dc_837242_8266a8 ✓六、解决三:cmake 与 ninja
Flutter 模块和部分 NDK 项目要跑 CMake。SDK 自带的 cmake 又是 x86_64……
Alpine 直接安装 ARM 原生的:
apk add cmake ninja
# 符号链接到 SDK 期望的位置
mkdir -p /opt/android-sdk/cmake/3.22.1/bin
ln -sf $(which cmake) /opt/android-sdk/cmake/3.22.1/bin/cmake
ln -sf $(which ninja) /opt/android-sdk/cmake/3.22.1/bin/ninja七、进阶:Flutter Add-to-App 模块
很多现代 App 是混合架构:原生壳 + Flutter 聊天 UI + Flutter Web。要编译这种项目,还要装 Flutter SDK:
# 用 git clone 安装 Flutter(比官方 tar 包更可控)
git clone --depth 1 --branch stable https://github.com/flutter/flutter.git /opt/flutter
export PATH="/opt/flutter/bin:$PATH"
export FLUTTER_ROOT="/opt/flutter"
# 触发 Dart SDK 下载(约 200MB,网络不稳会失败,多试几次)
flutter --version
# 在 Flutter 模块目录生成 Gradle 集成
cd 项目目录/ui && flutter pub getflutter pub get 会自动生成 .android/ 模块,包含 :flutter Gradle 项目。构建时它会自动:
- 编译 Dart →
kernel_blob.bin(debug 模式) - 下载
libflutter.so(Flutter 引擎,约 37MB) - 打包
flutter_assets/ - 运行
flutter build web生成 Web 聊天 UI
八、完整构建流程(一键脚本)
把以上经验固化成脚本 setup-arm64-sdk.sh,之后每次构建只需:
# 1. 设置 ARM64 SDK(只需一次)
bash setup-arm64-sdk.sh # 自动检测项目 NDK 版本、下载 ARM64 工具
# 2. 设置环境变量
export ANDROID_HOME=/opt/android-sdk
export ANDROID_SDK_ROOT=/opt/android-sdk
export PATH="/opt/flutter/bin:$PATH"
export FLUTTER_ROOT="/opt/flutter"
# 3. 构建
cd 项目目录 && ./gradlew assembleDebug我实际编译了一个 12+ 模块、含 Flutter 的项目(OpenOmniBot),结果:
BUILD SUCCESSFUL in 7m 55s
APK 大小:178 MB(debug 版)
包含:Flutter 引擎 + Dart 代码 + Web UI + NDK 原生库九、大文件下载的坑:断点续传
手机网络不稳定,330MB 的 NDK 经常下到一半断了。curl -C - 断点续传是救命稻草:
# 下载中断后,重新执行会自动从断点继续
curl -sL -C - --max-time 290 -o ndk.7z <下载地址>验证完整性再解压:
7z t ndk.7z && 7z x ndk.7z
# 如果报 "Unexpected end of archive",说明没下完,继续续传十、总结:手机编译安卓 App 的完整心法
| 坑 | 解法 |
|---|---|
| aapt2/aidl/zipalign 是 x86_64 | termux-ndk 的 ARM64 build-tools 替换 |
| NDK 是 x86_64 | termux-ndk 的 aarch64 NDK + 伪装版本号 |
| cmake 是 x86_64 | apk add cmake ninja + 符号链接 |
| Flutter 模块 | git clone Flutter SDK + flutter pub get |
| 大文件下载中断 | curl -C - 断点续传 + 7z t 校验 |
| 环境变量 | ANDROID_HOME / ANDROID_SDK_ROOT / FLUTTER_ROOT |
一句话总结:手机编译安卓 App 完全可行,核心就是把 x86_64 工具全部换成 ARM64 原生版,lzhiyong/termux-ndk 这个仓库解决了 90% 的问题。
附:完整的 setup-arm64-sdk.sh
所有步骤已固化为脚本,带自动检测、断点续传、重试上限,拿走即用:
#!/bin/sh
# setup-arm64-sdk.sh - 一键配置 ARM64 Android 编译环境
# 用法: sh setup-arm64-sdk.sh [项目目录]
set -e
SDK_DIR="${ANDROID_HOME:-/opt/android-sdk}"
NDK_VERSION="${1:-28.2.13676358}"
# 1. 系统包
apk add --no-progress cmake ninja p7zip
# 2. NDK(termux-ndk aarch64)
[ -f "$SDK_DIR/ndk/$NDK_VERSION/source.properties" ] || {
curl -L -C - -o /tmp/ndk.7z \
https://github.com/lzhiyong/termux-ndk/releases/download/android-ndk/android-ndk-r29-aarch64.7z
cd "$SDK_DIR/ndk" && 7z x /tmp/ndk.7z
mv android-ndk-r29 "$NDK_VERSION"
mkdir -p "$NDK_VERSION/platforms"
echo "Pkg.Desc = Android NDK
Pkg.Revision = $NDK_VERSION" > "$NDK_VERSION/source.properties"
}
# 3. build-tools(ARM64)
curl -L -C - -o /tmp/sdk.7z \
https://github.com/lzhiyong/termux-ndk/releases/download/android-sdk/android-sdk-aarch64.7z
7z x /tmp/sdk.7z "android-sdk/build-tools/35.0.0/*" -o/tmp/
cp /tmp/android-sdk/build-tools/35.0.0/{aapt2,aidl,zipalign} "$SDK_DIR/build-tools/35.0.0/"
# 4. cmake/ninja
mkdir -p "$SDK_DIR/cmake/3.22.1/bin"
ln -sf "$(which cmake)" "$SDK_DIR/cmake/3.22.1/bin/cmake"
ln -sf "$(which ninja)" "$SDK_DIR/cmake/3.22.1/bin/ninja"
echo "✅ ARM64 编译环境就绪!"如果你也在手机上折腾安卓开发,欢迎收藏转发。遇到问题评论区留言,我们一起踩坑一起填坑。 🚀
夜雨聆风