当前位置:首页>安卓APP>邪修 OpenClaw:在安卓手机上部署 小龙虾 的那些坑

邪修 OpenClaw:在安卓手机上部署 小龙虾 的那些坑

  • 2026-11-11 23:35:32
邪修 OpenClaw:在安卓手机上部署 小龙虾 的那些坑

背景

前阵子琢磨着把手边闲置的安卓手机利用起来,能不能跑个 OpenClaw 试试?

OpenClaw 是一个本地化的 AI Agent 框架,按理说它应该能在任何能跑 Node.js 的环境中运行。但我搜了一圈,发现大家的部署环境基本都是:

  • • 主力电脑
  • • 闲置电脑
  • • 云服务器
  • • 树莓派之类的嵌入式设备

很少有人提在安卓手机上跑。这就让我很好奇了:安卓手机本质上就是 Linux 内核,理论上应该也能跑才对。

说干就干,开始我的"邪修"之路。

准备工作

硬件建议:

  • • 安卓手机:建议 4G + 64G 以上(越大越好,Node.js 依赖包挺占空间的)
  • • Android 版本:10+

我用的设备:

  • • 手机:三星 Galaxy A54
  • • 安卓版本:15
  • • 软件环境:AidLux(手机上的 Linux 环境,Termux 也能用)
  • • OpenClaw 版本:2026.2.6-3

什么是 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 地址
  • • 一般是 192.168.x.x 的形式

第二步:安装 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 的初始配置,包括:

  • • 选择默认模型
  • • 配置 API keys(如果用云模型的话)
  • • 设置工作目录

到这里,看起来一切都很顺利,对吧?别急,真正的坑才刚刚开始。

遇到的坑

说实话,我一开始以为就是装个 Node.js 跑个 npm install 的事,但现实狠狠地打了我的脸。

坑 1:缺少环境工具

AidLux 作为一个精简的 Linux 环境,很多开发工具默认是没有的。

具体来说:

  • • 无 git 环境:克隆代码库的时候会报错
  • • 无 cmake 环境:编译某些原生模块时会失败
  • • cmake 环境版本过低:有些依赖需要高版本的 cmake

这些问题都需要自己一个个解决。

比如 cmake 的问题,我参考了这篇博客才搞定:https://blog.csdn.net/weixin\_65657501/article/details/140773580

文章里提到了如何在 AidLux 中编译安装高版本的 cmake,步骤挺繁琐的。

坑 2:内存占用自动销毁

这个坑比较隐蔽,刚开始的时候没发现。

长时间运行 OpenClaw 后,内存占用会越来越大。安卓系统的内存管理机制会检测到 AidLux 占用过多内存,然后直接把它 kill 掉。

这就导致:

  • • 刚开始部署时一切正常
  • • 用着用着突然断了
  • • 回到手机发现 AidLux 已经被关了

这个问题的本质是:安卓手机不是为长时间运行服务器程序设计的。

坑 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() 方法来获取网络接口信息,这个方法在以下场景都会被用到:

  • • 获取本机 IP 地址(用于显示、识别设备)
  • • 初始化网络监听
  • • bonjour 服务发现
  • • tailnet 功能

但在 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. 真正的痛点:它不能作为正式助手

上面这些都是技术问题,但最根本的问题是:

安卓手机不能作为后续个人的正式助手。

为什么?

  • • 稳定性问题:随时可能被系统杀掉
  • • 功能受限:很多技能跑不了
  • • 性能瓶颈:手机 CPU 性能有限
  • • 电池问题:长时间运行会耗尽电量

如果你只是想体验一下 OpenClaw,或者做一些轻量级的测试,安卓手机可以试试。

但如果你想要"满血体验",想要稳定可靠地运行各种技能,还是得用:

  • • 电脑(主力或闲置)
  • • 云主机(注意:是云服务器,不是云沙箱那种阉割版环境)

其他尝试方向

虽然这次在安卓手机上的尝试不算完美,但折腾本身就是意义。

除了安卓手机,OpenClaw 还可以部署在:

  • • 主力电脑虚拟机:性能好,但资源开销大
  • • 闲置电脑:可能是性价比最高的方案
  • • 云主机:稳定,但要花钱
  • • 嵌入式设备:树莓派之类,有趣但配置低
  • • 其他:Nas、软路由等...

如果你手头有闲置设备,不妨都试试,说不定能发现一些有趣的玩法。

总结

这次在安卓手机上部署 OpenClaw 的尝试,虽然遇到了不少坑,但最终算是跑通了。

让我回顾一下整个过程中的关键点:

  1. 1. AidLux 提供了在安卓上跑 Linux 的能力,这是基础
  2. 2. 环境配置要耐心,缺什么装什么,别嫌麻烦(git、cmake、npm 源...)
  3. 3. 最大的坑是权限问题,通过魔改源码加 try-catch 解决了
  4. 4. 一定要禁用 bonjour(OPENCLAW_DISABLE_BONJOUR=1),否则还会踩坑
  5. 5. 最终跑通了,还发现了拍照这个隐藏技能,这是意外之喜

虽然实用性有限,但至少证明了 OpenClaw 的可移植性还不错。Node.js 能跑的地方,理论上 OpenClaw 也能跑。

对于想体验 OpenClaw 又没有合适设备的同学,可以考虑这个方案。但如果有条件的话,还是建议在电脑或云主机上部署,体验会好很多。


折腾的价值在于过程,不在于结果。

这就是这次"邪修"的全部记录。

如果你也折腾过类似的方案,欢迎交流!

最新文章

随机文章