上篇聊了我怎么把 Agent 塞进手机——就是那条蓝色大肥鱼。那篇有个前提没细说:Agent 的内核是我用 Python 写的,而安卓 app 本身是 Kotlin。两种语言,怎么让它在一个安装包里一起跑?
这篇就聊这个最底层、也最无聊的一步:把 Python 塞进 APK。
先说我是怎么选的
要让 Python 代码在手机上跑,路大概两条:
一条是把活都丢给服务器,app 只当个壳,发请求、收结果;另一条是把 Python 解释器和你的代码一起编进安装包,在手机本地跑。
我这个项目一开始的定位就是"本地优先、不连我的服务器、密钥用户自己填",所以第一条路直接 pass,只能走第二条。于是 Chaquopy 出场了。
一句话介绍它:Chaquopy 是个 Gradle 插件(Gradle 就是 Android Studio 用来打包的那个构建工具)。装上之后,它能把 Python 解释器连同你的 .py 文件一起打进 APK,app 里用 Kotlin 直接调 Python 的函数,反过来 Python 也能调安卓的接口。
接入:主要动三个地方
比想象中简单。下面版本号都是我仓库里真实在用的。
1. 根目录的 build.gradle.kts,加插件声明和版本:
Chaquopy 17 这个版本官方说兼容安卓构建插件 7.3 到 9.2,我用的 8.13,对得上。
2. app 模块的 build.gradle.kts,真正启用它,并告诉它 Python 代码在哪、用哪个 Python 来构建:
srcDir 指到我的 kernel 目录,打包时那里面所有 .py 都会被收进去。
3. 就这两处。 Sync 一下,Gradle 会自动去下 Chaquopy 的运行时。
坑 1:buildPython 这个最容易懵
这里有个最容易踩的点,我也是懵了一阵才明白:Chaquopy 不是在手机上现编译你的 Python,而是在你电脑上,用一个 Python 把代码"冻结"进包里。 所以你这台电脑必须装一个和构建目标同大版本的 Python。
我图省事,用的是 Python 3.12 的便携版,放在仓库的 .tools/python312,然后用一个 Gradle 参数 -PhachimiPython 覆盖默认值。这样别人 clone 下来,只要本机有 3.12,构建命令一跑就能用,不用改配置。
构建命令长这样:
仓库里我也留了个 build_apk.bat,把 JAVA_HOME、ANDROID_HOME 都设好了,双击就能编。
坑 2:maven 镜像超时
第一次构建卡了很久,现象是卡在下载依赖,最后超时失败。后果是第一次构建半天下不来,我还以为是自己代码写错了。
定位之后发现是本机直连 repo.maven.apache.org 和 dl.google.com 超时——这俩是安卓依赖的来源。修法很简单:我写了个 Gradle 的 init script,把这几个仓库临时重定向到国内镜像(阿里云),用 -I 参数挂上去就行,不污染项目本身的配置。
提醒一句:这是国内搞安卓构建绕不开的环境摩擦,真不是你代码的问题。新开项目前先把镜像或代理备好,能省掉跟我一样的半天瞎排查。
坑 3:ABI 只留 arm64
另一个坑是包体积。Chaquopy 默认会给多种 CPU 架构都打一份原生组件,比如 arm64 和 x86_64。后果是包直接翻倍,构建也慢。
我的真机是 arm64,模拟器暂时不常用,所以在原生构建配置里把架构只留了 arm64-v8a:
注释里我也写了:等哪天要在 x86_64 模拟器上跑,再加回去。研究阶段先只打真机架构,别贪全。
坑 4:内核只用标准库(这点不是坑,是规矩)
值得单独说一句:我的 Python 内核(那个 hachimi_kernel 包)只用标准库,不装任何 pip 包,更不引 torch、OCR 那类重活。需要视觉和大模型的能力,全走 API。
带来的好处很实在:打包出来体积小、构建快、没有那些乱七八糟的本地库兼容问题。
教训一句话:app 里的 Python 尽量保持瘦,把重活交给云端 API,你和用户都轻松。
值不值
最后说句实话,Chaquopy 不是银弹。
适合它的场景:你手上已经有 Python 代码想进 app、想本地跑、又不想自己搭服务器——像我这种"内核是 Python、壳是 Kotlin"的,它很顺。
不适合的场景:如果你要在手机本地跑大量 numpy / torch 推理,那体积和兼容性会让你头疼,那种情况不如直接上服务器或者专门的推理框架。
在这个项目里,它干的事很清晰:Agent 的循环、记忆、技能都是 Python,屏幕操作和 UI 是 Kotlin,中间靠 Chaquopy 桥一下。跑通之后的体验就是——一个 app,两套语言,用户完全无感。
下篇接着聊什么
如果接着写,我想聊打包之后最麻烦的一件事:Python 已经打进 APK 了,可它跟 Kotlin 壳怎么"接起来"——两边怎么互相调用、数据怎么在两层之间传过去再传回来。前面感知与执行那篇(双通道感知)讲了两条通道能干什么、代价是什么,但没讲这两层语言在 app 里到底是怎么打通的。那一步才是 Agent 真正能跑起来的前提。
仓库还是那个:github.com/momo-null/hachifish