Pixel + Termux 复用 Mac OAuth Token 跑 Claude Code
在 Pixel 10 Pro Fold(Android 16)的 Termux + Ubuntu proot 容器里运行
claude-run,复用 Mac 上同款 Anthropic OAuth Token,完全替换原来的 Kimi 反代方案。
1. 背景
- 设备:Pixel 10 Pro Fold(代号
rango)/ Android 16,bootloader 已解锁,Magisk root - 原方案:claude-code 通过 Kimi Coding Plan 反代(
https://api.kimi.com/coding/),用 Kimi token 走所有请求 - 新目标:直连
api.anthropic.com,复用 Mac 上~/.zshrc里的CLAUDE_CODE_OAUTH_TOKEN,使用真正的 Claude Opus 4.7 - 动机:Frida 在 Android 16 无法跑(ptrace/CFI/SELinux 多重限制),后续工作转向 LSPosed + 真 Claude 模型,需要 Pixel 端本地也能跑 claude-code
2. 架构总览
┌─────────────────────────────────────────────────────────────┐
│ Termux (Android shell, user u0_a327) │
│ │
│ ~/.bashrc │
│ └─ export CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-... │
│ │
│ /usr/bin/claude-run ←─ wrapper │
│ └─ proot-distro login --shared-home ubuntu │
│ -- env CLAUDE_CODE_OAUTH_TOKEN="..." claude "$@" │
│ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Ubuntu proot container │ │
│ │ /root ←(--shared-home)─→ /data/data/com.termux/.../home│
│ │ ├─ .claude.json ← claude 主配置 │ │
│ │ └─ .claude/settings.json ← per-user settings │ │
│ │ │ │
│ │ claude (ELF/glibc, Node.js) │ │
│ │ └─→ HTTPS api.anthropic.com │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
关键点:
- Claude Code 是 ELF/glibc 编译,Android Bionic 跑不了 → 必须 proot 跑 Ubuntu
--shared-home把 Termux home 绑定为容器/root,配置文件可以从 Termux 端直接编辑- Token 通过
env KEY=VAL claude在容器内瞬时注入,不进容器 shell 环境
3. Claude Code 的双重认证闸门
这是整个迁移最关键的认知 —— claude-code 启动时有两道独立闸门:
| 闸门 | 检查内容 | headless (claude -p) |
交互模式 (claude) |
|---|---|---|---|
| ① Token 闸门 | CLAUDE_CODE_OAUTH_TOKEN env 或 ~/.claude/.credentials.json 任一存在 |
必须过 | 必须过 |
| ② Onboarding 闸门 | ~/.claude.json 的 hasCompletedOnboarding === true |
跳过 | 必须过 |
Kimi 反代为什么"屏蔽"了 Onboarding 闸门:它的 .env 块在启动时被 claude-code 注入进进程,等价于一直在用 API key 模式,OAuth onboarding 检查被旁路掉了。一旦切回官方 Anthropic,闸门被激活,于是裸 claude-run 弹出 OAuth URL。
4. 完整改动清单
按依赖顺序(缺一不可):
4.1 改 wrapper:注入 OAuth Token
文件:/data/data/com.termux/files/usr/bin/claude-run
#!/data/data/com.termux/files/usr/bin/sh
# Claude Code via proot-distro with shared home + Mac OAuth token
exec proot-distro login --shared-home ubuntu -- env CLAUDE_CODE_OAUTH_TOKEN="sk-ant-oat01-<...>" claude "$@"
权限:chmod 711(owner 可读,其他 app 不可读),owner u0_a327:u0_a327。
Token 直接 inline 到 wrapper,避免依赖 shell 启动文件。Android 沙箱保证其他 app 读不到
/data/data/com.termux/下的文件。
4.2 写 settings.json:清理 Kimi 痕迹
文件:/data/data/com.termux/files/home/.claude/settings.json
{
"env": {},
"model": "opus",
"skipDangerousModePermissionPrompt": true,
"theme": "dark"
}
权限:chmod 600。
env必须为空{}—— 之前 Kimi 配置在这里塞了ANTHROPIC_BASE_URL/ANTHROPIC_API_KEY等,会覆盖 wrapper 注入的 token。
4.3 清理 ~/.claude.json 的 env 块(最容易漏的一步)
文件:/data/data/com.termux/files/home/.claude.json
claude-code 的"主配置文件",顶层有个 env 字段会在进程启动时被 setenv 进去,优先级高于 wrapper 传入的 env。
操作(用 jq 在 Mac 端处理后 push 回去):
jq 'del(.env)
| .customApiKeyResponses.rejected = []
| .model = "opus"
| .hasCompletedOnboarding = true
| .lastOnboardingVersion = "2.1.144"' \
~/.claude.json.backup > ~/.claude.json.cleaned
需要保证:
.env字段被删除(不是设为空,是整个 key 不存在).hasCompletedOnboarding = true← 过 Onboarding 闸门.lastOnboardingVersion = "2.1.144"← 与当前 claude-code 版本对齐.model = "opus"(之前 Kimi 用的"opus[1m]"在官方 API 不存在).customApiKeyResponses.rejected = [](清掉之前 reject 过的 Kimi key 历史)
权限:chmod 600,owner u0_a327:u0_a327。
5. 完整执行脚本(从 Mac 端一键执行)
#!/usr/bin/env bash
set -euo pipefail
# 1. 从 Mac ~/.zshrc 提取 token
TOKEN=$(awk -F= '/^export CLAUDE_CODE_OAUTH_TOKEN=/{sub(/^export CLAUDE_CODE_OAUTH_TOKEN=/, ""); print; exit}' ~/.zshrc)
[ -z "$TOKEN" ] && { echo "ERROR: token not found in ~/.zshrc"; exit 1; }
# 2. 构造文件
mkdir -p /tmp/claude-pixel
cat > /tmp/claude-pixel/claude-run <<EOF
#!/data/data/com.termux/files/usr/bin/sh
exec proot-distro login --shared-home ubuntu -- env CLAUDE_CODE_OAUTH_TOKEN="$TOKEN" claude "\$@"
EOF
chmod 711 /tmp/claude-pixel/claude-run
cat > /tmp/claude-pixel/settings.json <<'EOF'
{
"env": {},
"model": "opus",
"skipDangerousModePermissionPrompt": true,
"theme": "dark"
}
EOF
# 3. 处理 .claude.json(先 pull,patch,push)
adb shell "su -c 'cp /data/data/com.termux/files/home/.claude.json /sdcard/cc.json && chmod 644 /sdcard/cc.json'"
adb pull /sdcard/cc.json /tmp/claude-pixel/cc.json
adb shell "su -c 'rm /sdcard/cc.json'"
jq 'del(.env)
| .customApiKeyResponses.rejected = []
| .model = "opus"
| .hasCompletedOnboarding = true
| .lastOnboardingVersion = "2.1.144"' \
/tmp/claude-pixel/cc.json > /tmp/claude-pixel/cc.patched.json
# 4. push & 安装
adb push /tmp/claude-pixel/claude-run /sdcard/claude-run.new
adb push /tmp/claude-pixel/settings.json /sdcard/settings.json.new
adb push /tmp/claude-pixel/cc.patched.json /sdcard/cc.json
adb shell "su -c '
WRAPPER=/data/data/com.termux/files/usr/bin/claude-run
SETTINGS=/data/data/com.termux/files/home/.claude/settings.json
MAIN=/data/data/com.termux/files/home/.claude.json
# 备份原版(只备份一次)
[ ! -f \$WRAPPER.prekimi ] && cp \$WRAPPER \$WRAPPER.prekimi
[ ! -f \$MAIN.prekimi ] && cp \$MAIN \$MAIN.prekimi
# 安装新版
cp /sdcard/claude-run.new \$WRAPPER
chown u0_a327:u0_a327 \$WRAPPER && chmod 711 \$WRAPPER
mkdir -p \$(dirname \$SETTINGS)
cp /sdcard/settings.json.new \$SETTINGS
chown u0_a327:u0_a327 \$SETTINGS && chmod 600 \$SETTINGS
cp /sdcard/cc.json \$MAIN
chown u0_a327:u0_a327 \$MAIN && chmod 600 \$MAIN
# 清理
rm /sdcard/claude-run.new /sdcard/settings.json.new /sdcard/cc.json
echo done
'"
# 5. 清理 Mac 临时文件
rm -rf /tmp/claude-pixel
6. 验证
6.1 headless 模式
adb shell 'su u0_a327 -c "
export HOME=/data/data/com.termux/files/home
export PATH=/data/data/com.termux/files/usr/bin:\$PATH
cd \$HOME
claude-run -p \"reply with just OK\" < /dev/null
"'
期望输出:OK(前面有几行 proot warning: can't sanitize binding /proc/self/fd/... 是 adb 非 tty 模式的良性警告,无视)。
6.2 交互模式(用户在 Termux 里直接跑)
$ claude-run
期望:直接进入 Claude Code TUI 界面,不弹出 OAuth URL。
6.3 排错检查清单
| 症状 | 检查 |
|---|---|
报错指向 kimi.com/code/console |
~/.claude.json 的 env 块没删干净 |
| 弹出 OAuth 登录 URL | ~/.claude.json 的 hasCompletedOnboarding 不是 true |
Failed to authenticate. 401 |
Mac 那边的 token 已失效,去 Mac 重新登录刷新 |
Warning: no stdin data received in 3s |
headless 模式没加 < /dev/null,等 3 秒后会继续,不是错误 |
which claude-run 指向其他路径 |
PATH 优先级问题 / 装了 alias |
7. 回滚
之前的版本都备份在 .prekimi 后缀文件里:
adb shell "su -c '
cp /data/data/com.termux/files/usr/bin/claude-run.prekimi /data/data/com.termux/files/usr/bin/claude-run
cp /data/data/com.termux/files/home/.claude.json.prekimi /data/data/com.termux/files/home/.claude.json
echo rolled back to Kimi config
'"
8. 安全注意
- Wrapper 里 inline 的 OAuth token 是个长效凭证,泄露等于账号被借用
- 文件权限:wrapper
711(不可读其他 app),.claude.json600 - Android 沙箱保证其他 app 无法访问
/data/data/com.termux/下的文件 - 如果手机丢失或共享,Mac 端立刻去 Anthropic console 撤销该 token(一撤销 Mac/Pixel 同时失效,需要重新登录刷新)
9. 已知限制
- 网络出口:直连
api.anthropic.com需要稳定国际网络。Pixel 在 4G 蜂窝下不一定通,建议挂代理或走 Wi-Fi - 计费归属:使用 Mac 同一个 Anthropic 账号配额,Pixel 跑多了会消耗 Mac 同账号的 quota
- Token 刷新:OAuth access token 有效期约 1 年,过期后需要在 Mac 端重新执行 OAuth 流程刷新,然后把新 token 同步到 Pixel wrapper
- 多设备 token 复用合规性:Anthropic ToS 允许同一账号在多设备使用,但禁止把 token 分享给第三方
10. 相关文件索引
| 路径 | 作用 |
|---|---|
/data/data/com.termux/files/usr/bin/claude-run |
wrapper(inline token) |
/data/data/com.termux/files/usr/bin/claude-run.prekimi |
旧版备份 |
/data/data/com.termux/files/home/.claude.json |
claude-code 主配置 |
/data/data/com.termux/files/home/.claude.json.prekimi |
主配置备份(含 Kimi) |
/data/data/com.termux/files/home/.claude/settings.json |
per-user settings |
/data/data/com.termux/files/usr/var/lib/proot-distro/containers/ubuntu/rootfs |
Ubuntu 容器 rootfs |
Mac 端:
| 路径 | 作用 |
|------|------|
| ~/.zshrc 里的 CLAUDE_CODE_OAUTH_TOKEN | Token 来源 |
| ~/.claude.json | Mac 上对应的主配置(参照对比用) |