Files
pangolin/docs/p1-macos-system-extension.md
T
wangjia b25c8bbc2c
ci-pangolin / Lint — shellcheck (push) Has been cancelled
ci-pangolin / OpenAPI Sync Check (push) Has been cancelled
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (push) Has been cancelled
ci-pangolin / Flutter — analyze + test (push) Has been cancelled
feat(client/macos): P1 方案B 骨架 — System Extension + NETunnelProviderManager 接线
把 PoC 的 sudo sing-box 外部二进制换成自包含、免 root 的 NEPacketTunnelProvider
(System Extension)+ 嵌入 libbox 的生产架构铺好骨架(不破坏现有 PoC 构建)。

- PacketTunnel/:扩展 target 源 — PacketTunnelProvider(LibboxSetup→NewService→start,
  openTun 建 NEPacketTunnelNetworkSettings)、Info.plist(NEProviderClasses)、
  entitlements(packet-tunnel-provider-systemextension + App Group)
- Runner/VpnChannel.swift:主 app 经 NETunnelProviderManager 启停 + 状态/速率回传,
  对齐 Dart 侧 VpnNativeBridge 的 pangolin/vpn channel 契约
- vpn_bridge_provider.dart:kUseNativeVpnMacOS 开关(默认 false,联调通过后置 true)
- docs/p1-macos-system-extension.md:文件清单 + Xcode/签名步骤 + 待办
  (Team BYL4KQHMTN;Network Extensions 已确认自助开通、无需 Apple 审批)

非破坏:新源文件未入 build target、注册行/app-group entitlements 均注释、gate 默认 false。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 11:07:36 +08:00

6.3 KiB
Raw Permalink Blame History

P1 · macOS System Extension 接线指南(方案B)

状态:骨架已落(本仓库)。把 PoC 的 sudo sing-box run 外部二进制换成自包含、免 root 的 NEPacketTunnelProvider(System Extension)+ 嵌入式 libbox。本文档列清单 + 待人工在 Xcode/开发者后台完成的步骤。总览见 vpn-core-embedding.md

0. 关键标识(已确定)

Team ID BYL4KQHMTN
主 app bundle id com.pangolin.pangolin(App ID 已注册,勾 Network Extensions + App Groups)
隧道扩展 bundle id com.pangolin.pangolin.tunnel(待注册,同样勾 Network Extensions + App Groups)
App Group group.com.pangolin.pangolin(待在 Identifiers → App Groups 注册)
分发方式 站外 Developer ID + 公证(非 App Store)→ entitlement 用 -systemextension 后缀
权限审批 无需——Network Extensions 在 Identifiers 自助勾选即得(Packet Tunnel Provider 已 GA)

1. 仓库里已就位的文件(骨架)

client/macos/
├─ Runner/
│  ├─ DebugProfile.entitlements / Release.entitlements  ← application-groups 已备(注释,待 §3.6 解开)
│  ├─ MainFlutterWindow.swift                           ← VpnChannel 注册行已备(注释,待 §3.6 解开)
│  └─ VpnChannel.swift                                  ← 主app:NETunnelProviderManager 启停+状态/速率回传(待加入 target)
└─ PacketTunnel/                                        ← 新 System Extension target 的源
   ├─ PacketTunnelProvider.swift                        ← 扩展:LibboxSetup→NewService→start;openTun 建 TUN
   ├─ PacketTunnel.entitlements                         ← packet-tunnel-provider-systemextension + app group
   └─ Info.plist                                        ← NEProviderClasses → PacketTunnelProvider

client/lib/bridge/
├─ vpn_bridge.dart            ← VpnNativeBridge(method/event channel,已存在)
└─ vpn_bridge_provider.dart   ← kUseNativeVpnMacOS 开关(默认 false;原生就绪后置 true)

Channel 契约(VpnNativeBridgeVpnChannel):

  • MethodChannel pangolin/vpn:start(configJson) / stop / getStatus / selectOutbound(tag) / getActiveOutbound / setKillSwitch(bool)
  • EventChannel pangolin/vpn/status:状态字符串(on/connecting/off/…)
  • EventChannel pangolin/vpn/stats:每秒一帧 {up, down, uplinkTotal, downlinkTotal}

2. 开发者后台(你来做,几分钟)

  1. App Group:Identifiers → App Groups → group.com.pangolin.pangolin
  2. 回到 App ID com.pangolin.pangolinApp Groups capability → Edit → 勾上该 group。
  3. 新建 App ID com.pangolin.pangolin.tunnel(扩展)→ 勾 Network Extensions + App Groups(关联同一 group)。
  4. Developer ID Application 证书(Certificates → ,若还没有)——签名 + 公证用。

3. Xcode:新增 System Extension target + 接 libbox(核心人工步骤)

Flutter 工程开 client/macos/Runner.xcworkspace

  1. 编 libbox:bash scripts/build-libbox.sh apple macos → 得 Libbox.xcframework(~204MB,不入 git)。
  2. 新 target:File → New → Target → Network Extension(macOS)→ Packet Tunnel
    • Product Name:PacketTunnel,bundle id com.pangolin.pangolin.tunnel,语言 Swift。
    • 删掉模板生成的 PacketTunnelProvider.swift,把 client/macos/PacketTunnel/ 下的三个文件 加入该 target(Provider/Info.plist/entitlements);Info.plist 与 entitlements 设为本 target 用。
  3. 链接 libbox:把 Libbox.xcframework 拖进工程,在 PacketTunnel target 的 Frameworks and Libraries 加入(Embed & Sign);解开 PacketTunnelProvider.swiftimport Libbox 与被注释的真实接线段(LibboxSetup/LibboxNewService/service.start())。
  4. 补平台接口:PangolinPlatformInterfaceLibboxPlatformInterfaceProtocol 的完整实现 (openTun / writeLog / useProcFS / findConnectionOwner / defaultInterfaceMonitor / getInterfaces / underNetworkExtension / systemCertificates …)——对照官方 sing-box-for-apple ExtensionPlatformInterface 逐方法移植(NE 部分两端高度一致,可大段复用)。这是 P1 唯一"重"的代码块。
  5. sysex 激活:VpnChannel.activateSystemExtensionIfNeeded()OSSystemExtensionRequest.activationRequest(forExtensionWithIdentifier: tunnelBundleId, queue:)
    • delegate 等结果;首启用户在「系统设置 → 隐私与安全性」点允许。
  6. 接主 app(Runner):
    • client/macos/Runner/VpnChannel.swift 加入 Runner target 的 Compile Sources
    • 解开 MainFlutterWindow.swiftVpnChannel.register(...) 那行注释。
    • 解开 Runner/DebugProfile.entitlementsRelease.entitlementsapplication-groups 注释块 (注册 App Group 后)。

    这三处在仓库里有意保持注释/未接,以免在 target/签名就绪前破坏现有 PoC 构建。

  7. 签名:两个 target(Runner + PacketTunnel)都用 Team BYL4KQHMTN + Developer ID; 开 Hardened Runtime;Runner 的 System Extensions capability 自动带出。

4. 速率/状态联调(libbox CommandServer)

  • 扩展内 LibboxNewCommandServer(loopback)暴露状态/速率/连接;主 app 用 LibboxCommandClient 订阅 → 回填 pangolin/vpn/stats…/status(替换 VpnChannel 里的占位 timer)。
  • 连接页(connect_page.dart)与统计页已消费这两路流,无需改动

5. 切换上线

  • 全部联调通过(连真节点、出口 IP=节点、速率/延迟、Kill Switch、退出拆隧道、明暗/中英)后, 把 vpn_bridge_provider.dartkUseNativeVpnMacOStrue
  • PoC 的 DesktopVpnBridge(sudo 子进程)保留作 fallback/调试,不删。

6. 待办清单(TODO,代码内已标 TODO(P1))

  • 开发者后台:App Group + 扩展 App ID + Developer ID 证书(§2)
  • Xcode:新 PacketTunnel target + 加入 Libbox.xcframework(§3.13.3)
  • 解开 PacketTunnelProvider.swift 真实接线 + 移植 PangolinPlatformInterface(§3.4)
  • OSSystemExtensionRequest 激活流程(§3.5)
  • LibboxCommandClient 接速率/状态(§4)
  • setKillSwitch / selectOutbound 真实实现
  • 签名 + 公证流水线(Team BYL4KQHMTN)
  • 联调通过 → kUseNativeVpnMacOS = true(§5)