资讯详情

资讯详情

Bun 下一版要支持安卓了!但作者警告:千万别拿它写 App——TaoToken 视角下的 Termux 实测与 aarch64 构建验证

1. Bun 的 aarch64-linux-android 目标到底解决了什么问题Bun 官方在 PR oven-sh/bun#29675 里加了一个新的编译目标aarch64-linux-android。这个目标名拆开看就三件事——CPU 架构是 aarch64内核是 Linux用户态是 Android 的 bionic libc。它编出来的产物是一个 ARM64 的 PIE 可执行文件依赖只有libc、libm、liblog、libdl这几个 bionic 系统库。换句话说它是一个能在 Android 内核上跑的命令行二进制跟 Activity、JNI、AAR 那一套应用层完全没关系。这件事对谁有用主要是两类人。第一类是在 Termux 里折腾 Node.js 工具链的开发者。Termux 本身提供了一套接近 Linux 的命令行环境但 Node.js 在里面的安装一直比较别扭得用 Termux 自己维护的包版本经常滞后。Bun 如果官方出 Android 二进制理论上可以直接bun upgrade拿到最新版。第二类是想把 JS 运行时嵌进 Android 应用的人比如某个 App 想内置脚本引擎处理插件逻辑可以把 Bun 当子进程或动态库跑这跟 Node.js 嵌入移动端的玩法是一回事。但作者 Jarred Sumner 自己赶紧澄清了一句这不是用 Bun 构建 Android App而是在 Termux 里用 Bun或者把 Bun 嵌入到 Android 应用里。要做 Android App还是得走 Kotlin/Java 官方工具链或者 React Native、Flutter 这些跨端方案。Bun 在这里的角色是后端工具不是前端框架。这个边界必须先说清楚否则很容易被误解成Bun 要抢跨端饭碗。从 Node.js 兼容角度看这次 PR 修了 47 处运行时问题其中不少是 Android 独有的坑。比如process.platform在打包阶段被错误内联——Bun 把内置 JS 模块编译成二进制时会把process.platform这种常量直接替换掉之前替换用的是宿主机平台值结果交叉编译出来的 Android 版 Bun 里所有process.platform android的分支都被当成死代码消掉了。修复办法是给代码生成器加TARGET_PLATFORM和ARCH环境变量。再比如 DNS 解析全超时因为 Android 没有/etc/resolv.confc-ares 没法发现 DNS 服务器默认用127.0.0.1每次查询等 20 秒超时改成默认走 bionic 的getaddrinfo才解决。这些坑里有些其实不是 Android 独有的。比如timerfd_create之前用的是CLOCK_REALTIME相对间隔的定时器一旦遇到 NTP 校时就会被偏移应该用CLOCK_MONOTONIC。这个 bug 在所有 Linux 上都存在只是 Android 上时钟跳变更频繁所以更容易暴露。Jarred 顺手把这种全平台都该修但一直没人发现的问题也一并提到了 PR 里。所以这一节的核心结论是aarch64-linux-android这个目标让 Bun 能在 Termux 里作为命令行工具跑起来也能被嵌入 Android 应用当脚本引擎但它不改变 Android App 的开发方式。你可以在手机上跑脚本、跑 AI 编程 Agent、跑构建工具但别指望用它写 Activity。下面几节我会从 Termux 实测角度把安装、版本切换、构建配置和验证请求的步骤完整走一遍。2. Termux 里准备 Bun 运行环境的前置操作在 Termux 里跑 Bun第一步不是直接装 Bun而是先把 Termux 的基础环境理顺。Termux 默认的包源有时候会比较慢建议先换源再更新。打开 Termux执行pkg update pkg upgrade -y如果更新过程中卡在某个源上可以先用termux-change-repo命令切换镜像。这个命令会弹出一个文本界面让你选镜像组选一个延迟低的就行。更新完成后装几个基础工具pkg install -y curl wget git unzip tar clang makeclang和make是为了后面可能涉及的 native 模块编译准备的。虽然 Bun 本身是预编译二进制但如果你要跑一些带 native 依赖的 npm 包编译工具链还是得有。接下来确认一下当前设备的架构。Termux 里执行uname -m如果输出aarch64说明你的设备是 ARM64正好对应aarch64-linux-android这个目标。如果输出armv7l或armv8l那说明是 32 位 ARMBun 目前的 Android 目标只覆盖 aarch6432 位设备暂时跑不了官方二进制。这一点要先确认否则后面装上了也跑不起来。然后检查一下 Termux 的 API level。Android 的 bionic libc 在不同 API level 上行为有差异Bun 的 PR 里用的是 NDK r27cAPI 28的 sysroot 做交叉编译。Termux 里可以这样看getprop ro.build.version.sdk如果输出小于 28可能会遇到一些系统调用不可用的问题。不过 Termux 本身对低版本 Android 的支持也在收缩建议至少在 Android 10 以上折腾。还有一个容易被忽略的点Termux 的存储权限。如果你要把脚本或项目文件放在共享存储里需要先执行termux-setup-storage这个命令会请求存储权限授权后会在~/storage下建立软链接。不过对于跑 Bun 脚本来说直接放在 Termux 自己的 home 目录下更省事避免权限和路径问题。环境理顺之后还要考虑一个关键问题Bun 的 Android 二进制目前是实验性的官方发布渠道可能还没完全铺开。在正式版发布前你可能需要通过bun upgrade的 canary 通道或者直接从 GitHub Releases 下载对应aarch64-linux-android的产物。PR 里提到bun upgrade已经打通所以等下一版发布后Termux 里应该可以直接用bun upgrade切换版本。这里要提醒一句Termux 里的$PREFIX环境变量指向的是 Termux 自己的文件系统前缀通常是/data/data/com.termux/files/usr。Bun 装进去之后二进制会放在$PREFIX/bin下。如果你手动下载二进制记得给它可执行权限并放到PATH里chmod x bun-linux-aarch64-android mv bun-linux-aarch64-android $PREFIX/bin/bun这样bun --version就能直接调用了。下一节我会给出完整的安装与版本切换命令以及 aarch64 目标构建配置。3. 可复制的 Bun 安装、版本切换与 aarch64 构建配置这一节直接给可复制的命令和配置片段。先说过渡期的安装方式。在 Bun 官方 Android 二进制正式进入稳定通道之前你可以用官方安装脚本指定目标平台curl -fsSL https://bun.sh/install | bash -s bun-linux-aarch64-android如果脚本还没适配 Android 目标就手动从 GitHub Releases 下载。假设当前版本是1.2.x下载命令wget https://github.com/oven-sh/bun/releases/download/bun-v1.2.x/bun-linux-aarch64-android.zip unzip bun-linux-aarch64-android.zip cd bun-linux-aarch64-android chmod x bun mv bun $PREFIX/bin/bun装完之后验证bun --version bun --revisionbun --revision会输出类似1.2.xabcdef的字符串确认版本号符合预期。如果输出command not found检查$PREFIX/bin是否在PATH里echo $PATH | tr : \n | grep termux正常应该能看到/data/data/com.termux/files/usr/bin。版本切换方面Bun 支持bun upgrade和bun upgrade --canary。在 Termux 里bun upgrade bun upgrade --canary如果bun upgrade报错说找不到对应平台的产物说明当前发布通道还没覆盖aarch64-linux-android这时候只能手动下载。手动切换版本时建议保留旧版本二进制做回滚mv $PREFIX/bin/bun $PREFIX/bin/bun.bak # 下载新版本后 mv bun $PREFIX/bin/bun接下来是构建配置。如果你要用bun build --compile交叉编译出 Android 目标的可执行文件命令是bun build --compile --targetbun-linux-arm64-android ./src/index.ts --outfile ./dist/app-android这里的--targetbun-linux-arm64-android就是 PR 里打通的编译目标。注意目标名是bun-linux-arm64-android不是aarch64-linux-android前者是 Bun 自己的 target 命名后者是 Rust/LLVM 那套 triple 命名。两者指向同一个平台但写在bun build命令里要用 Bun 的写法。如果你在项目里用package.json声明平台限制可以这样写{ name: my-termux-tool, version: 1.0.0, os: [android], cpu: [arm64], scripts: { build:android: bun build --compile --targetbun-linux-arm64-android ./src/index.ts --outfile ./dist/app-android } }os: [android]这个字段在 PR 里也打通了npm 包安装时会根据process.platform返回的android来匹配。这样你的包在 Termux 里安装时就不会被平台检查拦下来。如果你用bunfig.toml做配置可以加一段构建相关的[install] optional true [build] target bun-linux-arm64-android不过bunfig.toml里的build.target是否生效取决于 Bun 版本建议还是以命令行--target为准。还有一个实际会遇到的点Termux 里没有/tmp临时目录是/data/local/tmp。Bun 内部已经做了替换但如果你自己的脚本里硬编码了/tmp需要改成export TMPDIR/data/local/tmp或者在脚本里用os.tmpdir()动态获取。这个坑在 PR 描述里专门提到了/tmp不存在会导致很多工具链行为异常。最后给一个完整的安装加验证脚本可以一次性复制到 Termux 里执行set -e pkg update pkg upgrade -y pkg install -y curl wget unzip ARCH$(uname -m) if [ $ARCH ! aarch64 ]; then echo 当前架构 $ARCH 不是 aarch64Bun Android 目标暂不支持 exit 1 fi VERSION1.2.x wget -q https://github.com/oven-sh/bun/releases/download/bun-v${VERSION}/bun-linux-aarch64-android.zip unzip -o bun-linux-aarch64-android.zip chmod x bun-linux-aarch64-android/bun mv bun-linux-aarch64-android/bun $PREFIX/bin/bun bun --version把VERSION换成实际发布版本号即可。下一节我会用 TaoToken 的统一 Key/API 通道来验证 Bun 脚本里的网络请求和模型调用。4. 用 TaoToken 统一通道验证 Bun 脚本请求与成功结果装好 Bun 之后怎么确认它在 Termux 里真的能跑网络请求、能调模型我用 TaoToken 的统一 Key/API 通道来验证。TaoToken 的 API 地址是https://taotoken.net/api它提供 OpenAI 兼容的接口所以 Bun 脚本里可以直接用fetch调。先拿 Key。访问https://taotoken.net/api-keys登录后创建一个 API Key。这个 Key 是统一通道的凭证后面所有请求都用它。注意不要把 Key 硬编码进提交到 git 的脚本里用环境变量export TAOTOKEN_API_KEYsk-你的key然后写一个最小的验证脚本check.tsconst apiKey process.env.TAOTOKEN_API_KEY; if (!apiKey) { throw new Error(TAOTOKEN_API_KEY 未设置); } const res await fetch(https://taotoken.net/api/v1/chat/completions, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${apiKey}, }, body: JSON.stringify({ model: gpt-4o-mini, messages: [ { role: user, content: 用一句话说明 Bun 在 Termux 里能做什么 }, ], max_tokens: 100, }), }); if (!res.ok) { const text await res.text(); throw new Error(请求失败 ${res.status}: ${text}); } const data await res.json(); console.log(data.choices[0].message.content);在 Termux 里跑bun run check.ts如果一切正常你会看到模型返回的一句话。这个过程验证了三件事Bun 在 aarch64 Android 上能启动、能执行 TypeScript、能发起 HTTPS 请求并解析 JSON。这三件事跑通说明运行时基本可用。如果你想验证流式输出把stream: true加上然后处理 SSEconst res await fetch(https://taotoken.net/api/v1/chat/completions, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${apiKey}, }, body: JSON.stringify({ model: gpt-4o-mini, messages: [{ role: user, content: 数到五 }], stream: true, }), }); const reader res.body?.getReader(); const decoder new TextDecoder(); while (reader) { const { done, value } await reader.read(); if (done) break; const chunk decoder.decode(value); for (const line of chunk.split(\n)) { if (line.startsWith(data: ) line ! data: [DONE]) { const json JSON.parse(line.slice(6)); const delta json.choices?.[0]?.delta?.content; if (delta) process.stdout.write(delta); } } }流式输出在 Termux 里跑通说明 Bun 的ReadableStream和TextDecoder在 Android 上工作正常。这两个 API 在 bionic 环境下有没有坑PR 里没细说但实测下来是能用的。再验证一下 DNS 解析。前面提到 Android 没有/etc/resolv.confBun 改成走 bionic 的getaddrinfo。你可以用一个简单的 DNS 查询脚本确认const res await fetch(https://taotoken.net/api/v1/models, { headers: { Authorization: Bearer ${apiKey} }, }); console.log(res.status); const models await res.json(); console.log(models.data?.length ?? no data);如果这个请求在 1 秒内返回说明 DNS 解析没有走 20 秒超时的老路。如果卡了很久才返回那可能是当前 Bun 版本还没包含 DNS 修复需要升级到包含 PR 的版本。还有一个实际场景在 Termux 里跑 AI 编程 Agent。很多 Agent 工具用 Node.js 或 Bun 写比如 Claude Code、OpenCode 这类。它们通常需要设置ANTHROPIC_BASE_URL或OPENAI_BASE_URL指向统一通道。以 Claude Code 为例在 Termux 里可以这样配export ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_API_KEY$TAOTOKEN_API_KEY然后启动 Agent 工具。如果工具本身是 Bun 写的它会直接用 Termux 里的 Bun 运行时如果是 Node.js 写的你可能需要先用 Bun 的 Node 兼容层跑bun run --bun node_modules/.bin/some-agent-cli--bun参数强制用 Bun 替代 Node 执行。实测下来大部分纯 JS 的 CLI 工具能跑起来但带 native 模块的工具可能会在node-gyp那一步卡住因为 Android 上编译 native 模块需要额外的头文件和链接配置。验证成功后你可以把check.ts扩展成一个小的命令行工具用bun build --compile编成 Android 可执行文件bun build --compile --targetbun-linux-arm64-android ./check.ts --outfile ./dist/check-android ./dist/check-android如果这个编译产物能直接跑说明--targetbun-linux-arm64-android这条链路是通的。下一节我会列出 Termux 里常见的报错和排查方法。5. Termux 里 Bun 常见报错与排查对照这一节按真实报错来。第一个高频错误是401 Unauthorized。如果你在跑 TaoToken 验证脚本时看到请求失败 401: {error:{message:Invalid API key}}先检查环境变量有没有传进去echo $TAOTOKEN_API_KEY如果输出为空说明export没生效或者你在新的 shell 会话里没重新 export。Termux 里每次开新窗口都是新会话建议把 export 写进~/.bashrc或~/.zshrc。另外检查 Key 有没有多余空格Bearer后面跟的 Key 不要带引号。第二个错误是local proxy failed或连接超时。Termux 里如果配了http_proxy或https_proxy环境变量Bun 的 fetch 会走代理但 Android 上代理配置经常不完整导致连接失败。排查env | grep -i proxy如果有输出先 unsetunset http_proxy https_proxy all_proxy然后重试。TaoToken 的 API 地址是直连的不需要额外代理配置。第三个错误是reading choices或Cannot read properties of undefined (reading choices)。这通常是因为响应体不是预期的 JSON 结构比如返回了 HTML 错误页。排查方法是先把原始响应打出来const text await res.text(); console.log(status:, res.status); console.log(body:, text.slice(0, 500));如果 body 是 HTML说明请求打到了错误的地址。检查 URL 是不是https://taotoken.net/api/v1/chat/completions注意/api和/v1都不能少。如果 body 是 JSON 但没有choices字段可能是模型名写错了或者账户额度不足。第四个错误是 OAuth 相关。如果你在 Termux 里跑 Claude Code 这类工具可能会遇到OAuth token expired or invalid这类工具默认走 Anthropic 的 OAuth 流程但在 Termux 里浏览器回调经常拿不到。解决办法是改用 API Key 模式设置export ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_API_KEY$TAOTOKEN_API_KEY然后确认工具支持 API Key 认证。如果不支持就得看工具文档有没有--api-key之类的参数。第五个错误是bun: command not found或cannot execute binary file。前者是 PATH 问题后者是架构不匹配。排查file $PREFIX/bin/bun正常应该输出ELF 64-bit LSB pie executable, ARM aarch64。如果输出x86-64说明你下错了架构的包。如果输出ARM, EABI5说明是 32 位 ARM当前 Bun Android 目标不支持。第六个错误是EACCES相关的系统调用失败。前面提到 Android 14 的 seccomp 策略会用EACCES拒绝某些系统调用而不是返回ENOSYS。如果你看到epoll_pwait2: EACCES pwritev2: EACCES memfd_create: EACCES说明当前 Bun 版本还没包含对应的 fallback 修复。升级到包含 PR 的版本或者临时用环境变量禁用相关特性。不过这个错误在正常跑脚本时不一定出现更多是在高并发或特定 IO 场景下暴露。第七个错误是os.homedir()或os.userInfo()抛异常。Android 的 bionic 没有应用 UID 对应的 passwd 项所以这些调用本来会炸。修复后会在EACCES/EPERM时返回空值或降级到/data/local/tmp。如果你看到Error: EACCES: permission denied, scandir /proc/stat说明os.cpus()或os.networkInterfaces()在尝试读/proc被 SELinux 拦了。这个在 API 30 上比较常见升级 Bun 版本可以缓解。第八个错误是spawn /bin/sh ENOENT。Android 上/bin/sh和/usr/bin/env都不存在shell 在/system/bin/sh。如果你用Bun.$或child_process.spawn调 shell需要显式指定await Bun.$/system/bin/sh -c echo hello;或者设置SHELL环境变量export SHELL/system/bin/sh排查完这些基本能覆盖 Termux 里跑 Bun 的主要坑。如果遇到其他报错先把bun --revision和uname -a的输出记下来再去对照 PR 里的修复列表。6. 在 Termux 里用 TaoToken 跑通 Bun 脚本的完整路径把前面的步骤串起来一条完整的路径是这样的先在 Termux 里确认架构是 aarch64装好基础工具链然后下载或升级到包含aarch64-linux-android目标的 Bun 版本。接着设置TAOTOKEN_API_KEY环境变量写一个最小的 fetch 脚本验证网络和 JSON 解析。跑通之后再根据你的实际场景决定是跑脚本、跑 Agent还是用bun build --compile编 Android 可执行文件。如果你要长期在手机上跑 AI 编程 Agent建议把环境变量写进 shell 配置并且用 TaoToken 的 Coding Plan 来管理额度。Coding Plan 的入口在https://taotoken.net/coding-plan适合需要持续调用模型的场景。如果只是偶尔验证脚本用 API Keys 页面创建的 Key 就够了。模型选择方面可以在https://taotoken.net/models看当前支持的模型列表。验证脚本里用的gpt-4o-mini只是示例你可以换成任何统一通道支持的模型。如果要做模型对话测试https://taotoken.net/chat可以直接在浏览器里试不用写代码。接入文档在https://taotoken.net/doc里面有各语言的接入示例和参数说明。Claude Code 相关的配置可以参考https://taotoken.net/ClaudeCodeAnthropic里面写了 Base URL、Key 和 Model ID 三件套怎么填。Console 在https://taotoken.net/console可以看调用记录和用量。最后说一个实际经验Termux 里跑 Bun 脚本最耗时的往往不是 Bun 本身而是网络请求和 native 模块编译。纯 JS 脚本跑起来很顺但一旦涉及node-gyp或需要编译的 npm 包就容易卡在头文件和链接库上。所以选工具时优先选纯 JS 实现的或者已经提供预编译二进制的。Bun 的--compile能把脚本打成单文件可执行程序在 Termux 里分发很方便但前提是脚本本身不依赖 native 模块。至于千万别拿它写 App这个警告实测下来确实如此。Bun 在 Termux 里的定位是命令行工具和脚本运行时它能帮你跑 Agent、跑构建、跑自动化但它不提供 Activity 生命周期、不处理 Android 权限、不打包 APK。要做 Android App还是老老实实走 Kotlin/Java 或跨端框架。把 Bun 当成手机上的一个高效脚本引擎这个预期就对了。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →