macOS / iOS / iPad / Android / Windows 四端一致——内核 urltest 经 REALITY 真实出站测 RTT
generate_204 测 RTT)。
但服务端下发的配置没有 clash_api → 内核不暴露出站组/urltest 历史 → 默认取不到,连接页显示 —。
正解:每个原生端在起内核前给配置注入 clash_api,再经本地 HTTP 取。这条链四端踩了一整天,逐一记此。
| 层 | 坑 | 解 |
|---|---|---|
| ① 内核不暴露 | 服务端 BuildClientConfig 渲染的配置无 experimental.clash_api → sing-box 不开出站组/urltest 历史接口 | 原生端起内核前注入 clash_api(127.0.0.1 本地监听)+ cache_file |
| ② libbox 取法错 | libbox CommandClient 一连接只订一种命令:同一 client addCommand(Status)+addCommand(Group) 只第一个生效,Group 永不回调 → urltest 恒空 | 速率走 Status;urltest 改走 clash HTTP(/proxies 读 history + /group/<name>/delay 刷新),与 Windows desktop bridge 同法 |
| ③ Dart 抢 sink | VpnNativeBridge.statsStream 每次访问都 receiveBroadcastStream();多订阅者(连接页速度 + ConnectionController 回写延迟)抢 EventChannel 的单一原生 sink,后订阅者赢、前者变哑 → 速度正常但延迟一直 — | 缓存成共享广播流 asBroadcastStream(),所有订阅者复用一条原生订阅 |
| ④ 直连实测覆盖 | 连接态下 nodes_provider._measure 直连 TCP 测节点被全局 TUN 本地接住,几 ms 返回假值,覆盖 urltest 真实 RTT(显示 3ms) | 连接态跳过直连实测,延迟只认 urltest;_onStats 在自动连到已运行隧道(_connectedNode==null)时回退 effectiveNode |
| 端 | 注入 clash_api | 采集 + app↔内核通道 |
|---|---|---|
| macOS | 扩展 PacketTunnelProvider.injectClashApi | 扩展是 root,容器与无 root 主 app 不同路径 → 主 app 连不上 command.sock。扩展内 StatsCollector 采集(libbox Status 取速率 + clash HTTP 取 urltest),主 app 经 NETunnelProviderSession.sendProviderMessage("stats") 拉 |
| iOS/iPad | 同 macOS(扩展内注入) | 同 macOS:扩展 StatsCollector + sendProviderMessage。(iOS 扩展/app 同用户、容器其实共享,但为与 macOS 一致仍走此路) |
| Android | PangolinVpnService.injectClashApi | VpnService 与 libbox 同进程:服务内直接连 command.sock 取速率 + pollClash 取 urltest,经 VpnEventBus 推 Flutter |
| Windows | desktop bridge 注入(_ensureClashApi) | sing-box 子进程 + clash HTTP:kernel_process.dart 读 /proxies history + 每 12 拍 /group/<name>/delay |
取法细则(四端一致):显示源 = /proxies 里各 URLTest 组成员的 history.last.delay(稳定、缓存住,单次探测失败不丢);/group/<name>/delay 只为让内核重测、写进 history;跳过 GLOBAL 选择器组。
延迟为 — 时,层层往内定位(macOS/iOS 可读主 app NSLog,Android 用 logcat):
[pangolin/stats] urltest[0]= diag=... —— app 收到的 urltest 是否空 + clash 原始响应;log.level=debug + 抓 urltest/gstatic 行,看内核 outbound reality-out available: NNNms 有没有出(分清"内核没算出"vs"外面没拿到");/group/delay 返回 {} 而 dl=0:多半是链路本身太差(探测往返跑不完),非 bug。scripts/build-libbox.sh 生成:apple macos|ios → Libbox.xcframework;android → libbox.aar(改小写放 app/kernel/dist/android/)。io.nekohasekai.libbox(非 libbox)。相关:流量记账口径 · macOS sysext realize 排障 · 代码见各端 StatsCollector / PangolinVpnService / kernel_process.dart。