上篇文章介绍了在手机termux下安装codex cli,在这个基础上我干了一件更狠的事,在手机上开发编译apk。
前两天谷歌AI Studio上线,一周就搓出25万个Android App,99%的用户之前从没写过代码。随便打几行提示词,一个番茄钟、一个拍照翻译器、一个木鱼功德App就出来了。
看起来,Android开发的门槛已经被踩到了地板上。
但有个问题没人提:这些App是怎么装到手机上的?
答案是——你得有一台电脑,装上Android Studio,下载几个GB的SDK,然后点Run。
那如果我告诉你,我连电脑都没用,直接在手机终端里,把一个Android APK从零编译出来了呢?
我干了什么
一部手机,装个Termux,敲几行命令,48秒,一个54KB的APK就出来了。
能装,能跑,能用。
不是什么Hello World,是一个正经的AI语音助手——能录音、能语音识别、能调大模型聊天、能用TTS把回答念出来,还有悬浮球拖来拖去。

- Gradle构建——和电脑上Android Studio一模一样的流程,
./gradlew assembleDebug,一行命令出包 - 纯命令行手工编译——aapt2、javac、d8、zip、apksigner,七步流水线,不依赖任何构建工具
两种都跑通了。
核心突破:一行配置救活Gradle
先说为什么这事儿之前没人干成。
Gradle构建Android项目时,AGP会从Maven下载aapt2——一个资源编译工具。但下载下来的是x86-64版本。
Termux跑在ARM64上。
x86-64的二进制在ARM64上直接跑,结果就是:
Exec format error
就这么致命。
以前的解决办法是绕过Gradle,用手工编译。但现在有了更优雅的方案——在gradle.properties里加一行:
android.aapt2FromMavenOverride=/data/data/com.termux/files/usr/bin/aapt2
告诉Gradle:别下载Maven上的aapt2了,直接用Termux系统里已经装好的ARM64版本。
一行配置,Gradle瞬间复活。
实测:48秒,32个任务,一个APK
我拿一个AI语音助手项目做了测试。
项目信息:
- 包名:
com.ai.voiceassistant - 7个Java文件,1206行代码
- 目标SDK:Android 34
- 最低支持:Android 8.0
构建过程:
./gradlew assembleDebug
> Task :app:compileDebugJavaWithJavac
> Task :app:dexBuilderDebug
> Task :app:packageDebug
> Task :app:assembleDebug
BUILD SUCCESSFUL in 48s
32 actionable tasks: 32 executed
48秒,32个任务,全部通过。
产出的APK:54KB。adb install直接装。
和电脑上的体验几乎没有区别。唯一的区别是——你是在手机终端里敲的命令。
手工编译:七步流水线,每一步都看得见
如果你想搞清楚一个APK到底是怎么从源码变成可安装文件的,手工编译是最好的学习方式。
七步:
aapt2 compile → 编译资源文件(XML/PNG → .flat)
aapt2 link → 生成APK骨架 + R.java
javac → 编译Java源码
d8 → .class → .dex(Android字节码)
zip → 把dex塞进APK
zipalign → 4字节对齐
apksigner → 签名(v1+v2+v3)
核心代码:
# 逐文件编译资源(aapt2的--dir在Termux下有bug)
find "$SRC/res" -type f | while read f; do
aapt2 compile "$f" -o "$BUILD/compiled_res/"
done
# 链接生成APK
aapt2 link --manifest AndroidManifest.xml -I android.jar \
-o app-unsigned.apk --java gen --auto-add-overlay
# 编译Java
javac -source 17 -target 17 -classpath android.jar -d classes ...
# DEX转换
d8 --min-api 26 --output dex/ classes/*.class
# 打包、对齐、签名
cp app-unsigned.apk app-merged.apk
zip -j app-merged.apk dex/classes.dex
zipalign -f 4 app-merged.apk app-aligned.apk
apksigner sign --ks debug.keystore --out final.apk app-aligned.apk
每一步干什么,清清楚楚。
以前在Android Studio里点一下Run就完事的事,现在你亲手走了一遍。这种理解,在调试构建问题时特别有用。
两种方案怎么选?
| Gradle构建 | 手工编译 | |
|---|---|---|
| 适合 | 标准项目、有第三方库 | 简单项目、学习原理 |
| 依赖 | Gradle + AGP | 只需SDK命令行工具 |
| 速度 | 48秒 | 更快(跳过Gradle开销) |
| 依赖管理 | 自动下载 | 全部手动 |
| 上手难度 | 低 | 中 |
我的建议:先用Gradle日常开发,有空时用手工编译走一遍流程。
我踩过的四个坑
坑1:aapt2 --dir会崩
Termux的aapt2(2.19版)用--dir编译整个资源目录会段错误。解决:逐文件编译。虽然看着原始,但稳。
坑2:uses-sdk导致签名失败
AndroidManifest.xml里写了<uses-sdk>,apksigner报v1签名错误。解决:不让aapt2 link自动生成<uses-sdk>。
坑3:TTS念Emoji
大模型回复带Emoji,TTS引擎念出来声音很诡异。解决:正则过滤掉Emoji再送给TTS。
坑4:ASR和TTS互相打架
TTS说话时麦克风会把声音也录进去,形成回声。解决:加1.5秒冷却时间。
实际项目长什么样
这个"AI语音助手",核心链路就一条:
说话 → 语音识别 → 大模型回复 → TTS念出来
7个Java文件的分工:
| 文件 | 干什么 | 行数 |
|---|---|---|
| VoicePipeline.java | 语音管线状态机(IDLE→LISTENING→THINKING→SPEAKING) | 293 |
| FloatWindowService.java | 悬浮窗服务+脉冲动画 | 284 |
| MainActivity.java | 配置界面 | 240 |
| LlmClient.java | 大模型HTTP客户端,对接OpenAI兼容API | 172 |
| TtsManager.java | 语音合成+Emoji过滤 | 120 |
| ConversationManager.java | 对话历史管理 | 64 |
| DebugLog.java | 调试日志 | 33 |
全部Java,没有Kotlin,没有第三方库。54KB。
环境搭建速查
# 基础工具
pkg update && pkg install -y openjdk-17 gradle aapt2
# Android SDK(手动下载)
mkdir -p ~/android-sdk/{platforms,build-tools}
# 放入 android-34 platforms 和 build-tools 34.0.0
# 环境变量
export ANDROID_HOME=$HOME/android-sdk
export JAVA_HOME=$PREFIX/lib/jvm/java-17-openjdk
总占用:SDK约200MB,JDK约150MB。
Vibe Coding和手动编译,到底什么关系?
说实话,不矛盾。
谷歌AI Studio的Vibe Coding降低了门槛——不会写代码的人也能做出App。这是好事。
但如果你想理解App是怎么构建的,想掌控每一个字节是怎么变成APK的,想在没有电脑的时候也能独立开发——Termux给了你这个能力。
Vibe Coding是"让AI帮你搓"。
Termux手工编译是"你自己搓,每一步都知道发生了什么"。
两种方式,看你需要哪种。
试试看
如果你有一部Android手机,装个Termux,花10分钟搭好环境,然后:
# 验证环境
java -version
aapt2 version
gradle --version
# 创建一个最简单的项目,跑一遍构建
体验一下在手机终端里编译出APK的感觉。
那种"我亲手把源码变成了可安装文件"的掌控感,是点一下Run给不了的。
以上内容全部在Termux里完成
夜雨聆风