背景
前阵子琢磨着把手边闲置的安卓手机利用起来,能不能跑个 OpenClaw 试试?
OpenClaw 是一个本地化的 AI Agent 框架,按理说它应该能在任何能跑 Node.js 的环境中运行。但我搜了一圈,发现大家的部署环境基本都是:
很少有人提在安卓手机上跑。这就让我很好奇了:安卓手机本质上就是 Linux 内核,理论上应该也能跑才对。
说干就干,开始我的"邪修"之路。
准备工作
硬件建议:
- • 安卓手机:建议 4G + 64G 以上(越大越好,Node.js 依赖包挺占空间的)
我用的设备:
- • 软件环境:AidLux(手机上的 Linux 环境,Termux 也能用)
什么是 AidLux?
AidLux 是一个能在安卓手机上运行完整 Linux 环境的应用。它不是模拟器,而是通过容器技术共享 Android 的 Linux 内核,在用户空间运行一个 Linux 发行版,所以性能损失很小。
AidLux 下载地址: https://developer.aidlux.com/software/aidlux
当然,你也可以用 Termux,但 AidLux 的体验更好,自带了图形化的终端和一些开发工具。
实操步骤
第一步:安装 AidLux
在手机上安装 AidLux,它会给你一个完整的 Linux 环境。
安装完成后,你需要连接到 AidLux 进行操作。
浏览器远程控制
在电脑上通过浏览器访问 http://192.168.xx.xx:8000 连接到手机,账号密码相同。
这种方式的好处是:直接在电脑的浏览器里就能操作手机里的 Linux 环境,键盘输入方便,还能复制粘贴代码,体验最好。
如何找到手机 IP 地址?
- • 在 AidLux 应用首页会显示你的 IP 地址
第二步:安装 Node.js v24
AidLux 默认没有 Node 环境,需要自己安装。
我用的是 nvm(Node Version Manager)来管理 Node 版本,这样以后切换版本也方便。
先安装 nvm:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash
安装完成后,需要重新加载一下 shell 配置(或者直接重启终端):
source ~/.bashrc
然后安装 Node.js v24:
nvm install 24
验证安装是否成功:
node -v # 应该显示 v24.x.xnpm -v # 显示 npm 版本
第三步:配置 npm 国内源
不配置国内源的话,npm install 会慢到怀疑人生。
npm config set registry https://registry.npmmirror.com
验证是否生效:
npm config get registry# 应该显示 https://registry.npmmirror.com
第四步:安装 OpenClaw
npm install -g openclaw@latest
安装过程可能需要几分钟,因为要下载大量的依赖包。
第五步:初始化配置
openclaw onboard
这个命令会引导你完成 OpenClaw 的初始配置,包括:
到这里,看起来一切都很顺利,对吧?别急,真正的坑才刚刚开始。
遇到的坑
说实话,我一开始以为就是装个 Node.js 跑个 npm install 的事,但现实狠狠地打了我的脸。
坑 1:缺少环境工具
AidLux 作为一个精简的 Linux 环境,很多开发工具默认是没有的。
具体来说:
- • 无 cmake 环境:编译某些原生模块时会失败
- • cmake 环境版本过低:有些依赖需要高版本的 cmake
这些问题都需要自己一个个解决。
比如 cmake 的问题,我参考了这篇博客才搞定:https://blog.csdn.net/weixin\_65657501/article/details/140773580
文章里提到了如何在 AidLux 中编译安装高版本的 cmake,步骤挺繁琐的。
坑 2:内存占用自动销毁
这个坑比较隐蔽,刚开始的时候没发现。
长时间运行 OpenClaw 后,内存占用会越来越大。安卓系统的内存管理机制会检测到 AidLux 占用过多内存,然后直接把它 kill 掉。
这就导致:
这个问题的本质是:安卓手机不是为长时间运行服务器程序设计的。
坑 3:启动报错(这个最坑!!!)
这是整个过程中最让我崩溃的一个坑。
当我好不容易把所有环境都配置好,满心欢喜地输入:
openclaw gateway
结果直接给我报错:
SystemError [ERR_SYSTEM_ERROR]: A system error occurred: uv_interface_addresses returned Unknown system error 1 at Object.networkInterfaces (node:os:217:16) at resolvePrimaryIPv4 (file:///.../dist/infra/system-presence.js:15:21) at initSelfPresence (file:///.../dist/infra/system-presence.js:35:16)
这个错误的意思是: Node.js 在调用底层 API 获取网络接口信息时,系统返回了错误。
问题根源
OpenClaw 启动时会调用 os.networkInterfaces() 方法来获取网络接口信息,这个方法在以下场景都会被用到:
但在 AidLux 容器环境中,这个调用会因为没有足够的权限而失败。
这不是 OpenClaw 的 bug,而是 AidLux 的安全限制。容器化的 Linux 环境为了安全,会限制一些系统调用。
这个坑让我卡了好久,一度以为根本解决不了。
解决方案
既然 os.networkInterfaces() 调用会失败,那最直接的思路就是:在源码里给它加上 try-catch,出错的时候用一个备用方案。
这就是所谓的"魔改"源码了。
第一步:下载源码
我当时下载的是 v2026.2.6-3 版本,和你看到的草稿版本一致:
git clone -b v2026.2.6-3 https://github.com/openclaw/openclaw.gitcd openclaw
第二步:找到需要修改的文件
通过搜索源码,我找到了三个调用 os.networkInterfaces() 的地方:
src/gateway/net.ts: const nets = os.networkInterfaces();src/infra/system-presence.ts: const nets = os.networkInterfaces();src/infra/tailnet.ts: const ifaces = os.networkInterfaces();
这三个文件分别负责:
- •
src/gateway/net.ts:网关网络配置 - •
src/infra/system-presence.ts:系统信息收集 - •
src/infra/tailnet.ts:tailnet 网络功能
第三步:魔改源码(添加 try-catch)
修改 src/gateway/net.ts
vim src/gateway/net.ts
找到 pickPrimaryLanIPv4() 函数,加上 try-catch:
export function pickPrimaryLanIPv4(): string | undefined { try { const nets = os.networkInterfaces(); const preferredNames = ["en0", "eth0"]; for (const name of preferredNames) { const list = nets[name]; const entry = list?.find((n) => n.family === "IPv4" && !n.internal); if (entry?.address) { return entry.address; } } for (const list of Object.values(nets)) { const entry = list?.find((n) => n.family === "IPv4" && !n.internal); if (entry?.address) { return entry.address; } } return undefined; } catch { // 出错时返回主机名作为备用方案 return os.hostname(); }}
修改 src/infra/system-presence.ts
vim src/infra/system-presence.ts
找到 resolvePrimaryIPv4() 函数,加上 try-catch:
function resolvePrimaryIPv4(): string | undefined { try { const nets = os.networkInterfaces(); const prefer = ["en0", "eth0"]; const pick = (names: string[]) => { for (const name of names) { const list = nets[name]; const entry = list?.find((n) => n.family === "IPv4" && !n.internal); if (entry?.address) { return entry.address; } } for (const list of Object.values(nets)) { const entry = list?.find((n) => n.family === "IPv4" && !n.internal); if (entry?.address) { return entry.address; } } return undefined; }; return pick(prefer) ?? os.hostname(); } catch { // 出错时返回主机名作为备用方案 return os.hostname(); }}
修改 src/infra/tailnet.ts
vim src/infra/tailnet.ts
找到 listTailnetAddresses() 函数,加上 try-catch:
export function listTailnetAddresses(): TailnetAddresses { const ipv4: string[] = []; const ipv6: string[] = []; try { const ifaces = os.networkInterfaces(); for (const entries of Object.values(ifaces)) { if (!entries) { continue; } for (const e of entries) { if (!e || e.internal) { continue; } const address = e.address?.trim(); if (!address) { continue; } if (isTailnetIPv4(address)) { ipv4.push(address); } if (isTailnetIPv6(address)) { ipv6.push(address); } } } return { ipv4: [...new Set(ipv4)], ipv6: [...new Set(ipv6)] }; } catch { // 出错时返回主机名作为备用方案 return { ipv4: [os.hostname()], ipv6: [os.hostname()] }; }}
核心思路: 当 os.networkInterfaces() 调用失败时,catch 块会捕获异常,然后用 os.hostname() 返回主机名作为备用值。这样程序就不会崩溃了。
第四步:安装依赖并编译
魔改完源码,接下来就是常规的编译流程了:
# 安装依赖pnpm install# 构建 UI(首次运行会自动安装前端依赖)pnpm ui:build# 编译 TypeScriptpnpm build
这一步可能需要一些时间,因为要编译整个项目。
第五步:重新初始化配置
pnpm openclaw onboard --install-daemon
这个命令会:
第六步:启动 OpenClaw(关键!!!)
这是最后一步,也是最关键的一步。
一定要加上 环境变量!
OPENCLAW_DISABLE_BONJOUR=1 pnpm openclaw gateway
为什么必须加这个变量?
因为 bonjour 功能(苹果的 mDNS 服务发现)也会调用 os.networkInterfaces(),虽然我们在上面三个文件里加了 try-catch,但 bonjour 是一个独立的功能模块,它的调用路径我们没覆盖到。
加上这个环境变量后,OpenClaw 会禁用 bonjour 功能,避免再次踩坑。
启动成功! 🎉
终端里会显示 OpenClaw 的启动信息,如果看到类似 "Gateway started" 的日志,说明成功了。
"阿哈"时刻
终于把 OpenClaw 跑起来了!那一刻的成就感,简直无法形容。
除了常规的让小龙虾(我的 AI 助手昵称)做查询咨询之外,我开始想:小龙虾还能干点啥?
由于我的运行环境是安卓机器,我就想:能不能让它帮我拍个照?
一开始我以为这个功能肯定不支持,毕竟这是手机专有的功能。但我想试试看,就问了小龙虾:
"你能帮我拍张照吗?"
小龙虾一开始说它不会这个技能。但我不死心,继续跟它聊,让它试试调用手机摄像头。
经过几次摸索,它真的能拍照了!
小龙虾学会了拍照
拍照成功展示
更多拍照测试而且通过这次对话,小龙虾还把"拍照"这个能力沉淀成了自己的技能。以后再问它拍照,它就能直接调用了。
这个发现让我有点惊喜,也有点意外。原本以为只是个折腾的技术实验,结果真的跑出了点东西。
这就像是在玩一个游戏,本来只是为了通关,结果发现了一个隐藏的成就。
着实 666。
存在的问题
虽然折腾成功了,但冷静下来思考,安卓手机作为 OpenClaw 的运行环境,还是有很多局限性:
1. 能使用的技能少
很多技能是为桌面环境设计的,比如:
- • 系统命令(很多 Linux 命令在 AidLux 里是阉割版)
- • 开发工具(git、cmake 等需要自己手动安装)
2. 久了内存占用大,App 会被 kill
这个问题前面提到过,但真的很致命。
安卓的内存管理很激进,后台运行的应用会被频繁回收。AidLux 作为一个"外来户",更是会被优先处理。
这导致:
- • 用几个小时或者第二天回来,发现 AidLux 已经被关了
这个问题的本质是:安卓手机不是为长时间运行服务器程序设计的。
3. 权限不够
容器化的环境限制了很多系统调用:
这些限制虽然可以通过魔改源码绕过一部分,但本质上还是受限的。
4. 真正的痛点:它不能作为正式助手
上面这些都是技术问题,但最根本的问题是:
安卓手机不能作为后续个人的正式助手。
为什么?
如果你只是想体验一下 OpenClaw,或者做一些轻量级的测试,安卓手机可以试试。
但如果你想要"满血体验",想要稳定可靠地运行各种技能,还是得用:
- • 云主机(注意:是云服务器,不是云沙箱那种阉割版环境)
其他尝试方向
虽然这次在安卓手机上的尝试不算完美,但折腾本身就是意义。
除了安卓手机,OpenClaw 还可以部署在:
如果你手头有闲置设备,不妨都试试,说不定能发现一些有趣的玩法。
总结
这次在安卓手机上部署 OpenClaw 的尝试,虽然遇到了不少坑,但最终算是跑通了。
让我回顾一下整个过程中的关键点:
- 1. AidLux 提供了在安卓上跑 Linux 的能力,这是基础
- 2. 环境配置要耐心,缺什么装什么,别嫌麻烦(git、cmake、npm 源...)
- 3. 最大的坑是权限问题,通过魔改源码加 try-catch 解决了
- 4. 一定要禁用 bonjour(
OPENCLAW_DISABLE_BONJOUR=1),否则还会踩坑 - 5. 最终跑通了,还发现了拍照这个隐藏技能,这是意外之喜
虽然实用性有限,但至少证明了 OpenClaw 的可移植性还不错。Node.js 能跑的地方,理论上 OpenClaw 也能跑。
对于想体验 OpenClaw 又没有合适设备的同学,可以考虑这个方案。但如果有条件的话,还是建议在电脑或云主机上部署,体验会好很多。
折腾的价值在于过程,不在于结果。
这就是这次"邪修"的全部记录。
如果你也折腾过类似的方案,欢迎交流!