目标 v0.8.0 正在准备:Rust 0.3.0 / JS 0.2.0 / Lab 0.4.0 / server 0.2.0 / RAM-only 样例 0.1.0。完整仓库源码包将保留 SDK、服务和样例的相对依赖;外部 Noise adapter 不随包分发。该版本尚未发布,以下下载仍为不可变 v0.7.0,完整样例与生产验收仍单独记录。

首次部署

首次部署:从一份.env到Mac/Android互通

从一份服务端配置开始,按步骤完成两端登录、设备互见和双向传输;下方保留 SDK 接口参考。

登录同一应用,连接两端服务。

Rust 是主要 SDK。Release v0.7.0 的默认连接顺序为 WebRTC → iroh 直连 → Cloudflare 匿名隧道,也可选择 WebRTC / iroh 直连并行竞速;iroh 禁用 relay,仅使用纯数字 socket 地址。Go SDK 与历史 v0.6.0 的 Rust / Lab 包仍使用两级策略。

Release v0.7.0 的 Lab 0.3 使用官方 SDK 网页登录,macOS 与 Android 使用同一个关闭 Device Flow 的 Logto Native 应用。历史 Release 的 Lab 0.2 / CLI 设备码登录不适用于新的网页登录服务;请将本次协调服务与 Lab 0.3 一同升级。

选择平台与下载
连接验证与运行条件。 历史 v0.6.0 测试完成了 macOS / Android 的 Cloudflare 回退通信与当时内存协调服务的重启恢复。v0.7.0 的 iroh 路径及本轮 Redis / Functions 部署尚未完成 Wi-Fi / 4G 公网验收;历史结果只覆盖原测试网络。

下方 SDK 示例与下载对应历史 v0.7.0。当前未发布源码的静态产品、finite-v2、Rust 默认关闭 gate、JS directory/watch 与 gated bridge API,以各 SDK 源码 README 和 兼容说明为准;不得将旧下载直接视为已获得这些能力。RAM-only 模块尚需完整样例装配与真实云登录、手机和长跑验收。

选择需要的产物

系列运行环境内容
Rust SDK 0.2.0macOS / Android arm64原生 crate、示例与许可;通过 Cargo path 引用,通过 Cargo path 集成,不在 crates.io 分发
Lab 0.3.0macOS Apple Silicon / Android API 28+Tauri 2 测试 App ZIP / 测试 APK / 完整源码 / 许可证包
JS / TS SDK 0.1.0现代浏览器 / 官方 Logto 宿主只读源码包、ESM / 类型包与许可证;零运行依赖
Go SDK 0.4.0Go 1.27 / 两端 arm64 CLI嵌入库、命令行程序、构建脚本与许可

所有产物从 GitHub Release v0.7.0 下载,使用对应系列 manifest / SHA256SUMS 校验完整文件。原 APK 的许可证正文请同时下载,完整 Android ZIP 已携带正文。不要用另一系列或旧版本清单校验新文件。

下载后校验所选文件
# 将同系列 SHA256SUMS 与文件放在同一目录
# 仅校验你已下载的 Go macOS 包
grep 'cybergrid-sdk-0.4.0-macos-arm64.tar.gz' SHA256SUMS | shasum -a 256 -c -
tar -xzf cybergrid-sdk-0.4.0-macos-arm64.tar.gz
cd cybergrid-sdk-0.4.0-macos-arm64
./cybergrid-macos version

用 Tauri Lab 完成双端测试

  1. Mac 使用 SDK 随附并校验的固定 provider,无需另外安装;默认不搜索 PATH。Android 使用 SDK 资源生成的 jniLibs,安装后由 nativeLibraryDir 启动,同一 APK 只保留一份原生 provider。
  2. 两端填写同一个真实 Logto Native Application ID,不同本机名称。中央服务默认为 https://cybergrid.aixgg.com,新版本使用 memory-v1 协调协议。
  3. Mac 通过 GUI 发起登录;Android 用下方私有 ADB 工具发起。新版 Lab 会通过官方 SDK 打开系统浏览器完成 Logto 登录;不要复制授权文件。已有本机 v4 授权可显式恢复本机登录。
  4. Mac 在真实设备列表选择对端;Android 用 refresh / connect 命令连接消息端口。发送成功以对端 ack 为准;对端收发区应显示实际消息。
  5. 分别在两个方向执行 64 KiB 校验,核对字节数、SHA256 与实际 transport。Rust / Lab 默认按 WebRTC → iroh 直连 → Cloudflare 匿名隧道尝试,可在高级设置或 ADB 参数选择并行直连策略;强制回退会跳过两个直连阶段,仅作测试参数。
  6. 关闭窗口会关闭短会话和本机 provider、保留本机持久授权;退出登录先停止本次服务,再撤销本端 grant。撤销失败保留材料并提示。
安装 CI 构建的 Android 0.3 测试 APK
# 先核对本系列 SHA256SUMS
read -r ANDROID_SERIAL
adb -s "$ANDROID_SERIAL" install -r CyberGrid-Lab-0.3.0-android-arm64-test.apk
# 由 adb devices 取得本机实际序列号,不把个人设备标识写进公开配置。

macOS ZIP 解压后包含测试 App 和许可。该 App 未经 Apple 公证,Android 是 CI 临时 debug 签名测试包;与其他签名的已安装 App 不能原地升级,均不代表商店正式发布。Android 本轮支持前台测试,切到浏览器完成登录不会自动取消授权,但不承诺后台长期保活。

通过 ADB 控制 Android 测试 App

请下载 v0.7.0 的 CyberGrid-Lab-0.3.0-android-arm64-test.zip,解压后包含测试 APK、tools/android-adb.py 与许可证。只下载 APK 的用户还需从同版本完整 ZIP 或 Lab 源码包取得工具。历史 Lab 0.2 与新服务登录方式不兼容。它通过 adb run-as tech.tinadev.cybergrid.lab 向 App 私有控制目录提交命令,GUI 仍显示同一 LabState 的真实状态。无需 adb input、输入法、坐标点击或 WebView 注入。

入口仅在 Android debug 测试构建显式启用 adb-test-control feature 时提供;普通 release 不含入口,即使误传 feature 也不会启用。请使用同一版本的测试 APK 和源码工具;未启用时会明确失败。

选择工具路径 · 启动与独立登录
# 从 Lab 0.3 Android 完整 ZIP 解压目录执行
ADB_CONTROL=tools/android-adb.py
# 完整仓库则使用 apps/tauri-test/tools/android-adb.py;APK 与工具须为同一 Release。
# 从 adb devices 获取你的实际序列号;省略配置参数时使用预置测试配置
read -r ANDROID_SERIAL
python3 "$ADB_CONTROL" --serial "$ANDROID_SERIAL" start
python3 "$ADB_CONTROL" --serial "$ANDROID_SERIAL" status
python3 "$ADB_CONTROL" --serial "$ANDROID_SERIAL" web-login
# 在手机系统浏览器完成官方 Logto 登录后返回 App。
python3 "$ADB_CONTROL" --serial "$ANDROID_SERIAL" status
# 已有本机 v4 授权时使用 resume,不能复制 Mac 的授权文件。
# 自建服务可显式传 --server / --app / --name;不要混用不同服务的授权。
发现、连接与端到端验证
python3 "$ADB_CONTROL" --serial "$ANDROID_SERIAL" refresh
# 从 refresh 的真实设备列表取得对端逻辑 ID
read -r PEER_DEVICE_ID
python3 "$ADB_CONTROL" --serial "$ANDROID_SERIAL" connect --device-id "$PEER_DEVICE_ID"
python3 "$ADB_CONTROL" --serial "$ANDROID_SERIAL" send --text "来自 Android 的测试消息"
python3 "$ADB_CONTROL" --serial "$ANDROID_SERIAL" probe --device-id "$PEER_DEVICE_ID"
python3 "$ADB_CONTROL" --serial "$ANDROID_SERIAL" disconnect
# close 保留本机授权;不再使用时另执行 logout 撤销 grant。
python3 "$ADB_CONTROL" --serial "$ANDROID_SERIAL" close

cancel-login 调用原取消路径;logout 调用原撤销路径。不要 force-stop 或清空 App 数据替代安全关闭。send 的文本是本机测试输入,实际对端收件和 ack 由 SDK 的端到端通道完成;probe 使用原链路生成并验证 65,536 字节,不通过 ADB 灌入业务 payload。

超时或 App 重启会报告 OUTCOME_UNKNOWN,工具不会自动重发有副作用命令;先查询 status。受理回执不是登录、映射、对端收件或 hash 验证成功。工具不提供注入 token、任意 shell、替换证书或绕过 TLS 的入口,状态只返回安全字段。

使用真实 Logto 应用与独立授权

推荐用服务端 CYBERGRID_PRODUCTS 静态策略将真实 SPA / Native OAuth client 绑定到 canonical 产品;OAuth 应用仍在 Logto 管理,Native 关闭 Device Flow 并授予 resource 的 connect 用户权限。控制台复制的是 canonical 产品 ID,不可当成另一个 OAuth client ID。未配置静态策略时可选动态 Logto 目录,需要服务端 Management M2M 凭据。历史 v0.7 Lab 的应用输入仍是其真实 Native client_id,按对应发布版本使用。

新版 Lab 在 Android 使用官方 Logto Android SDK,macOS 前端使用官方 JavaScript SDK,通过授权码与 PKCE 在系统浏览器完成注册 / 登录;SDK 与 App 不收密码、PAT、M2M 或 client secret。登录完成后将最新 grant 一次性交接给 Rust 私有所有者,由 Rust 负责后续恢复、刷新与撤销。后续中央接口使用短期会话;OAuth refresh 保存在各自设备的私有所有者中。

明确指定公开 Native ID
# 历史 v0.7 Lab:从 Logto 取得真实 Native client_id,不能复制 canonical 产品 ID
read -r CYBERGRID_APP_ID
export CYBERGRID_APP_ID

Release v0.7.0 的 Rust SDK 示例

Rust SDK 默认启用 iroh 直连,位于 WebRTC 之后、Cloudflare 匿名隧道之前。可通过 iroh_enabled 关闭此阶段,通过 iroh_timeout 限定单次尝试;direct_strategy 可选默认的 Sequential 或 Parallel 直连竞速,relay 始终禁用。仅同账号、同应用的设备会取得候选地址,控制台及管理后台不显示 iroh 地址。Release v0.7.0 的源码包包含这些配置与连接路径。

解压源码包后,crate 根目录为 cybergrid-sdk-rust-0.2.0;Cargo.toml 位于该目录。若 my-app 与该目录同级,在 my-app/Cargo.toml 添加:

应用 Cargo.toml
[dependencies]
cybergrid-sdk = { path = "../cybergrid-sdk-rust-0.2.0" }
tokio = { version = "1", features = ["full"] }

path 相对当前应用的 Cargo.toml 解析。仓库中的 apps/tauri-test/src-tauri 使用 ../../../sdk-rust;下载完整 Lab 源码则保留包内 apps / sdk-rust / tools 相对目录。SDK 不调用 Go 或 Go FFI。

Rust · 已有私有授权的 CredentialStore 恢复
use cybergrid_sdk::{Client, CloudflaredConfig, Config, CredentialStore, Port};
use std::sync::Arc;

// macOS arm64:使用当前用户 OS cache base,SDK 管理其专用私有子目录。
let cache_base = std::path::PathBuf::from(std::env::var("HOME")?)
    .join("Library/Caches");
let client = Client::new(Config {
    app_id: std::env::var("CYBERGRID_APP_ID")?,
    cloudflared: Some(CloudflaredConfig::bundled(cache_base)?),
    ..Config::default()
})?;
// 真实宿主选择 app-private 目录;不要放在网页目录或日志中。
let store = CredentialStore::new("/absolute/private/device-v4.json");
client.use_credential_store(store.clone()).await?;
client.set_auth_provider(Arc::new(store.clone())).await;
// 首次登录由宿主官方 Logto SDK 完成,并通过 import_browser_grant 安全交接。
// 具体平台与 checkpoint / 所有权确认实现见当前 Lab 0.3 源码。
// 以下仅恢复这台设备已有的私有授权;不存在时应显示网页登录入口。
let tokens = store.refresh(&client).await?;
let session = client.login_with_access_token(&tokens.access_token, "my-device").await?;
client.expose(Port::tcp("sync", 6789, "my-sync-protocol")).await?;
let devices = client.devices().await?;
// 选择已公布 sync 端口的真实远端设备。
if let Some(remote) = devices.iter().find(|d| d.id != session.device_id && d.online) {
    let mapping = client.map(&remote.id, "sync", "127.0.0.1:0".parse()?).await?;
    println!("{}", mapping.addr);
    // 通过本地地址访问,使用完毕 mapping.close().await。
}
// 退出短会话 client.close().await?;退出授权另执行 store.logout(&client).await?。

此为 macOS arm64 的 async 函数内片段,使用已冻结的 bundled 构造;完整错误处理以源码 README 为准。Config.cloudflared 为 None 时不启动本地 provider,仍可连接远端已发布的隧道;new(path) 仅用于显式可信 external override。绑定私有 store 必须在首次 mint 前完成。取消停止后续轮询;一旦 token / refresh 请求已发出,不能 drop 整个 future,必须接管最新 grant 并完成保存或撤销。

历史 Rust 示例 · 仅兼容旧 Device Flow 服务
# 以下历史示例不适用于当前网页登录服务;新版首次登录请使用 Lab 0.3。
tar -xzf cybergrid-sdk-rust-0.2.0-source.tar.gz
cd cybergrid-sdk-rust-0.2.0
cargo test --locked --lib
cargo run --locked --example lab -- login --app "$CYBERGRID_APP_ID" --credentials /absolute/private/device-v4.json
cargo run --locked --example lab -- host --app "$CYBERGRID_APP_ID" --credentials /absolute/private/device-v4.json
# 另一台设备需自己的 grant 和凭据路径
cargo run --locked --example lab -- probe --app "$CYBERGRID_APP_ID" --credentials /absolute/other/device-v4.json --peer REMOTE_DEVICE_ID --bytes 65536

Release v0.7.0 的 JS / TS SDK 0.1.0

浏览器宿主使用官方 Logto JS / React SDK 完成登录,再把 getAccessToken 回调交给 CyberGridClient。CyberGrid SDK 只在内存保存只读 console 会话,查询应用、同账号设备以及端口明确申报的 port.tunnelUrl;它不注册设备、不发送信令、不代理业务请求。设备离线或未申报端口地址时返回空值,不使用设备内部加密隧道地址替代。

前端须固定可信 issuer、唯一控制台 SPA client ID 与 resource。跨域部署时,服务端配置精确的 CYBERGRID_BROWSER_ORIGINS 列表,并在 Logto 登记宿主回跳。业务端口自身仍须实现授权及所需 CORS。完整 API、构建与取消/恢复规则见 JS SDK 源码说明;Release v0.7.0 提供源码包与包含 ESM、类型声明、README 和许可的浏览器集成包。

Go SDK 与 CLI

Go module 路径为 github.com/ywateru/CyberGrid/sdk,组件版本 0.4.0。本次网页登录兼容修改随项目 Release v0.7.0 源码包交付,请下载该包并通过本地 replace 接入;历史子模块 tag sdk/v0.4.0 保持原内容。CLI 保留历史设备码登录入口,不支持新服务首次网页登录。完整可编译示例 examples/embed 使用私有 RAM grant 所有者,退出时完成撤销;需要跨进程持久化时使用宿主安全存储或 CLI 的 v4 锁文件。

自有 Go module
# 从项目 Release v0.7.0 下载并解压 cybergrid-sdk-0.4.0-source.tar.gz
# 在自有 module 中,替换为真实解压路径
go mod edit -replace=github.com/ywateru/CyberGrid/sdk=/absolute/path/cybergrid-sdk-0.4.0
go mod tidy
# 从解压的 cybergrid-sdk-0.4.0 根目录可 go test ./... 或 go run ./examples/embed

嵌入应用在任何 mint 前设置 SetGrantCheckpoint;回调必须实际保存或接管最新 refresh,失败后通过 RetryPendingGrant / RevokePendingGrant 解决私有 pending。自动恢复通过 Config.AuthProvider 或 SetAuthProvider 显式提供:AccessToken(context.Context,*Client) (OAuthTokens,error)。返回前保存轮换,不在后台自动打开 Device Flow。

Go · macOS 默认内置 provider
client, err := cybergrid.New(cybergrid.Config{
    BaseURL: "https://cybergrid.aixgg.com",
    AppID: os.Getenv("CYBERGRID_APP_ID"),
    TunnelProvider: cybergrid.Cloudflared{}, // 内置资源,默认 OS 用户 cache
})
if err != nil { return err }
defer client.Close()
// 必须先设置私有 GrantCheckpoint / AuthProvider,再开始授权。
// 首次网页登录由宿主官方 Logto SDK 完成,安全接管并保存最新 grant。
// 再调用 LoginWithAccessToken、Expose、Devices 与 Map。
// 历史 examples/embed 的 Device Flow 首次授权不适用于当前服务。
历史 Mac CLI · 仅兼容旧 Device Flow 服务
# 以下历史设备码登录命令不适用于当前服务;新版首次登录请使用 Lab 0.3。
mkdir -p "$HOME/.config/cybergrid"
chmod 700 "$HOME/.config/cybergrid"
./cybergrid-macos login -app "$CYBERGRID_APP_ID"   -credentials "$HOME/.config/cybergrid/mac-logto-v4.json" -open-browser
./cybergrid-macos host -app "$CYBERGRID_APP_ID"   -credentials "$HOME/.config/cybergrid/mac-logto-v4.json" -name mac -echo-port 0
# 另一台已独立授权设备执行 map / probe,保持提供端 host 运行。
./cybergrid-macos probe -app "$CYBERGRID_APP_ID"   -credentials "$HOME/.config/cybergrid/other-logto-v4.json"   -peer DEVICE_ID -port echo -bytes 65536 -no-tunnel

Expose 与 Map

Expose 声明本机 loopback 上已运行的 TCP 服务,端口 ID 与类型字符串由应用定义,最多32个。Map 只允许监听本机 loopback,可使用端口0;创建时真实验证远端端口可打开。SDK不会开放远端任意 IP、未发布端口或 UDP。

先用 Devices 核对同账号同应用的远端及已公布端口,选择真实逻辑设备 ID。业务层可以是 API、文件或同步协议;消息业务协议只属于 Lab / 自有应用,不写入 SDK 或中央。

Rust 的 WebRTC、iroh 直连与 Quick Tunnel 三条路径均有端到端 TLS1.3 双向认证和当前设备 fingerprint 校验;Go 保持 WebRTC / Quick Tunnel 两条路径。Rust 默认依序尝试两个直连阶段,也可选择并行竞速,失败后在独立预算内连接 Quick Tunnel;Cloudflare 终止外层 HTTPS,内层业务密钥由设备持有,中央不转发应用字节。

Vercel KV 与部署配置

Vercel 官方说明:旧 Vercel KV 已迁移到 Upstash Redis;新部署从 Vercel Marketplace 连接 Upstash Redis。CyberGrid 使用该资源自动注入的 KV REST 变量,不需要安装旧 @vercel/kv 包。

Vercel 项目环境变量
CYBERGRID_REDIS_TRANSPORT=vercel-kv
# 由 Marketplace 资源注入,保留私密:
KV_REST_API_URL
KV_REST_API_TOKEN
# 预览与生产使用不同的前缀:
CYBERGRID_REDIS_PREFIX

也可使用自己的 Upstash 账户创建数据库,将该数据库的 REST URL 与完整可写 token 手工填入 KV_REST_API_URL 和 KV_REST_API_TOKEN;无需将新资源连接到 Marketplace。Upstash 账户 API 管理密钥用于管理资源,不能填入运行时数据库 token。

使用可写 token,不使用 KV_REST_API_READ_ONLY_TOKEN。显式选择 vercel-kv 后仅使用 KV REST URL / token;缺少任一配置时拒绝启动,不会改用同时存在的 TCP 或 Upstash 变量。普通 Docker / Node 部署仍支持 tcp 与 upstash-rest,按所选传输配置相应变量。

已有部署切换传输时,必须保留同一数据库和同一个 CYBERGRID_REDIS_PREFIX,不要新建或清空数据库;这样继续使用原 namespace epoch。预览使用独立前缀,避免影响生产会话。免费资源的额度和使用量由提供商限制,持续轮询会消耗命令额度;不启用自动付费升级。

查看完整 Vercel Functions / KV 与 Logto 配置步骤;页面不接收或显示数据库 token。

协调失效后重新建立新连接

协调状态保存在 Redis 命名空间,普通 Function 或 Node 实例重启不会更换 epoch。Redis 命名空间初始化或重置会建立新 epoch;会话和设备按各自有效期回收。配置了显式 AuthProvider 的 SDK 单飞恢复注册,保持逻辑设备 ID、重新发布端口和本代证书 / provider URL。短网络故障采用退避,不为每次 poll 刷新 Logto。

原 Map 可以保留本地 listener 和远端逻辑 ID;恢复期间拒绝新连接,Ready 后新的 TCP 重新握手。旧 TCP 会中断,不重放业务字节或旧消息。业务应用应依照消息 ID / ack / 同步协议决定是否重试,不能按设备名把另一个设备当作原对端。

观察 coordination-ready、recovering、requires-login、mapping-disconnected / ready、provider-restarting / failed、closed 事件。Lab 恢复期间清旧连接成功状态并暂停发送,Ready 后只有重新握手和消息 ack 才显示成功。RequiresLogin、用户身份变化或 SESSION_SUPERSEDED 必须停止,不自动抢回会话。

v4 私有凭据与退出

当前 Go0.4 / Rust0.2 / Lab0.3 使用 version4,绑定 server、appId、issuer、clientId、resource、scope 与受信 Device / Token / Revocation endpoints;coordination epoch 是动态状态,不写进固定绑定。旧 v3 / v2 不自动导入、刷新或覆盖,原字节保留;新授权使用独立 v4 文件 / App 私有命名空间。

两端各自授权,不能复制 refresh 文件代替第二端登录。CLI 文件锁覆盖 mint 到 checkpoint;写盘失败时 pending 私有 owner 保留锁 lease,其他进程不能读旧 token 刷新。活进程会保留材料直到保存或撤销完成;provider 签发与本机落盘之间的进程崩溃窗口无法跨系统原子化。

Close 关闭本次短会话和自有资源,不等于撤销 Logto grant。Logout 先停止本端连接再撤销 grant,成功后删除私有文件,失败保留材料。旧 grant 用旧版按原配置或由 Logto 维护者显式撤销;删除文件不等于 provider 撤销。

撤销新的本机 v4 授权
./cybergrid-macos logout -app "$CYBERGRID_APP_ID" \
  -credentials "$HOME/.config/cybergrid/mac-logto-v4.json"

SDK 随附的 Cloudflared

Go SDK 0.4 与 Rust SDK 0.2 随包提供同一组固定 provider 资源,首批支持 macOS arm64 与 Android arm64/API 28+。macOS 使用官方 2026.9.0 darwin-arm64 原始 binary,Android 使用同版本固定 commit 的已记录 DNS 兼容补丁构建。源码包保留来源、archive/binary 校验清单、构建脚本、Apache 2.0 原许可与第三方声明。运行时不下载或自动更新 provider。

macOS:默认内置,不另装

Go 默认 Cloudflared 配置与 Rust 显式 bundled 构造选择内置资源。Go 可用 CacheDir/CLI -provider-cache 指定绝对 cache base;Android CLI 的 -native-library-dir 是显式安装目录,-cloudflared path 为受信 external override,不用于 App 默认接入。SDK 提取到当前用户私有 cache,按固定版本/hash 隔离,在跨进程锁内验证长度、SHA256、所有者与权限后执行。损坏、symlink 或不安全权限明确失败,不自动退回 PATH。只有调用方显式选择受信 external provider 时才使用外部程序;它不享有内置资源的固定字节保证。

Android:通过宿主原生安装目录启动

Go/Rust 随包的 Android 资源与离线脚本供宿主生成 jniLibs/arm64-v8a/libcloudflared.so,配置 native library 提取并禁止 strip。安装后将 ApplicationInfo.nativeLibraryDir 与 App 私有 cache 提供给 SDK 的 NativeLibraryDir/android_native 配置,SDK 只解析并校验固定文件。APK 仅保留一份原生 provider,不再 include 到编译库,也不在可写 files/cache 中解压执行。

每次 spawn 通过受控回调取得当前 LinkProperties DNS,TMPDIR 指向本 App cache;不沿用历史网络地址,不修改系统 DNS、路由、TUN 或代理。缺失安装目录、ABI 不支持、hash 不符或环境回调失败均明确报错,不改用 PATH、可写目录或 ADB shell provider 代替 App 自身启动。

provider 资源、来源与许可证随 GitHub Release 的 SDK 源码包提供,复现资料见 源码目录。新版 SDK/App 不需要另装外部 provider;请使用对应系列清单校验归档。

Go / Rust 解压根目录 · 宿主离线打包
python3 scripts/prepare-android-provider.py /absolute/host/app/src/main/jniLibs
# 仅复制校验后的 arm64-v8a/libcloudflared.so,不下载或运行 provider。
宿主 Gradle Kotlin 配置
packaging {
    jniLibs {
        useLegacyPackaging = true
        keepDebugSymbols.add("**/libcloudflared.so")
    }
}
Rust · Android 宿主构造函数
fn installed_provider(
    native_dir: std::path::PathBuf,
    app_cache: std::path::PathBuf,
    current_environment: cybergrid_sdk::ProviderEnvironment,
) -> cybergrid_sdk::Result<cybergrid_sdk::CloudflaredConfig> {
    let mut provider = cybergrid_sdk::CloudflaredConfig::android_native(
        native_dir, app_cache,
    )?;
    provider.env_provider = Some(current_environment);
    Ok(provider)
}
// 将返回值放入 Config.cloudflared = Some(provider)。
// current_environment 由宿主每次从当前 LinkProperties 生成 DNS 和 TMPDIR。
Go · Android 宿主 provider
func installedProvider(nativeDir, appCache string,
    currentEnvironment func() (map[string]string, error),
) cybergrid.Cloudflared {
    return cybergrid.Cloudflared{
        NativeLibraryDir: nativeDir,
        TempDir: appCache,
        EnvProvider: currentEnvironment,
    }
}
// 放入 Config.TunnelProvider;nativeDir 来自 ApplicationInfo.nativeLibraryDir。
// 回调每次读取当前网络并返回 CLOUDFLARED_DNS_SERVER 与 TMPDIR。

离线校验并执行 --version 只证明资源可以运行,不代表离线可建立 Cloudflare 隧道;Quick Tunnel 仍需要可用网络且无可用性保证。

实际测试与平台边界

邮箱验证与找回密码由 Logto 托管;实际邮箱收件链路尚未完成验收,发送成功不代表邮件已经送达。

默认直连优先不等于所有公网网络可打洞。本地 WebRTC / mTLS / smux 互通与 Wi-Fi / 4G 公网观察分开记录;历史 v0.6.0 已完成实机回退与当时内存协调服务的重启恢复验证;这些记录仅证实原网络下的 Cloudflare 回退。本轮 Redis / Functions 与 v0.7.0 iroh 的 Wi-Fi / 4G 公网验收仍待完成,不代表公网直连成功。

Quick Tunnel 无 uptime SLA;不提供无损路径切换、UDP 映射、后台长期保活、应用层自动业务重放。中央会话最长24小时,online lease65秒;Logto 浏览器退出或账号禁用不保证即时撤销已交换的中央会话。应用失效由后续目录校验识别。