feat(ios): M3 PoC — PacketTunnelProvider + entitlement + 内存监控 [tsk_nsobbj_rJdy0]

### 新增文件
- client/ios/PacketTunnel/MemoryMonitor.swift
  周期打点 NE 进程内存(os_proc_available_memory iOS13+ / mach_task_basic_info 兼容
  iOS12);每 10s 采样一次;availableMemory < 5MB 时输出 ⚠️ 警告;提供
  summaryString() 供 handleAppMessage/getMemory IPC 返回。

- client/ios/PacketTunnel/PacketTunnel.entitlements
  Extension 的 NE + App Group entitlement 文件;申请说明写入注释。

- client/ios/Runner/Runner.entitlements
  主 App 的 NE + App Group entitlement 文件;申请说明写入注释。

- doc/ne-entitlement-申请指引.md
  完整申请操作手册:Bundle ID 清单、Apple Developer Portal 步骤、
  专项审批英文申请文案(已脱敏,无红线词)、审批 lead time 说明。

### 修改文件
- client/ios/PacketTunnel/PacketTunnelProvider.swift
  完整 M3 实现(替换原骨架 TODO):
  · startTunnel:解析 configJson(options/App Group 两路回退)→
    buildNetworkSettings → setTunnelNetworkSettings → setupTunBridge
    → startLibbox → startPacketBridging → memoryMonitor.start()
  · stopTunnel:memoryMonitor.stop() → stopLibbox → closeTunBridge
  · handleAppMessage:JSON IPC 协议(getStatus/getMemory/selectOutbound)
  · LibboxPlatformInterface 扩展(#if canImport(Libbox)):
    openTun 返回 socketpair libbox 侧 fd,autoDetectInterfaceControl no-op,
    writeLog 转 os.log,useProcFS 返回 false
  · packetFlow 双向桥接(readFromPacketFlow/writeToPacketFlow 循环)
  · parseTunAddress/parseDNSServers 从 JSON 提取网络参数

- client/ios/Runner/VpnManager.swift
  · localizedDescription "穿山甲 Pangolin VPN" → "Pangolin 加速"(红线词修复)
  · 新增 appGroup 常量(group.com.pangolin.pangolinVpn)
  · start() 写入 App Group UserDefaults 缓存 configJson

- client/ios/Runner/Info.plist
  NSVPNUsageDescription "穿山甲使用 VPN…" → "Pangolin 使用网络加速通道…"(红线词修复)

- client/ios/PacketTunnel/Info.plist
  CFBundleDisplayName "穿山甲 Tunnel" → "Pangolin 加速通道"(红线词修复)

- client/ios/Runner.xcodeproj/project.pbxproj
  · Runner + PacketTunnel 所有 build config 添加 CODE_SIGN_ENTITLEMENTS
  · 新增 MemoryMonitor.swift 到 PacketTunnel Sources 构建阶段
  · 新增 Runner.entitlements / PacketTunnel.entitlements / MemoryMonitor.swift
    文件引用及分组

- app/kernel/build-ios.sh
  添加 M3 内存裁剪决策记录:gVisor→grpc→QUIC 优先裁减顺序及内存估算,
  等待真机 10min 压测结果后更新最终结论

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-06-13 17:44:11 +08:00
parent ed5eabea58
commit e129f094c2
10 changed files with 889 additions and 41 deletions
+3 -2
View File
@@ -47,8 +47,9 @@
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<!-- VPN 使用说明(App Store 审核必填) -->
<!-- 网络隧道使用说明(iOS 系统必填,显示于系统权限对话框)
⚠️ 红线词规范:避免 VPN/翻墙 等词,使用「网络加速」口径 -->
<key>NSVPNUsageDescription</key>
<string>穿山甲使用 VPN 为您的网络连接提供加密保护。</string>
<string>Pangolin 使用网络加速通道为您的连接提供安全保护。</string>
</dict>
</plist>
+33
View File
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<!--
Runner.entitlements — 主 App Target Entitlements
Bundle ID: com.pangolin.pangolinVpn
申请说明:
1. com.apple.developer.networking.networkextension
→ "packet-tunnel-provider" 须在 Apple 开发者后台显式申请。
申请路径:developer.apple.com → Certificates, IDs & Profiles
→ Identifiers → com.pangolin.pangolinVpn → Capabilities
→ Network Extensions → Packet Tunnel Provider(勾选)
2. com.apple.security.application-groups
→ group.com.pangolin.pangolinVpn 须在 App Groups 注册。
主 App 与 PacketTunnel extension 共享同一 Group
用于 UserDefaults(suiteName:) / FileManager containerURL(forSecurityApplicationGroupIdentifier:)
传递少量共享状态(上次节点 tag、连接时间戳等)。
-->
<plist version="1.0">
<dict>
<!-- Network ExtensionPacket Tunnel Provider(主 App 控制面) -->
<key>com.apple.developer.networking.networkextension</key>
<array>
<string>packet-tunnel-provider</string>
</array>
<!-- App Group:主 App ↔ PacketTunnel extension 共享容器 -->
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.pangolin.pangolinVpn</string>
</array>
</dict>
</plist>
+12 -4
View File
@@ -1,14 +1,15 @@
// VpnManager.swift App NETunnelProviderManager
// VpnManager.swift App NETunnelProviderManager M3 PoC
//
//
// 1. loadAllFromPreferences / saveToPreferences VPN
// 2. start / stop NETunnelProviderSession PacketTunnel extension
// 3. sendProviderMessage IPC PacketTunnelProvider.handleAppMessage
// 4. NEVPNStatus VpnStatusStreamHandler.shared Dart
//
// AppDelegate MethodChannel handler
//
// TODO(11F): start/stop / NEVPNStatus
// VpnStatusStreamHandler.shared.eventSink Dart
// 线 VPN / / / / 穿 /
// Go anywherelocalizedDescription 使Pangolin
import Foundation
import NetworkExtension
@@ -65,6 +66,8 @@ class VpnManager: NSObject {
// Bundle ID PacketTunnel target PRODUCT_BUNDLE_IDENTIFIER
private let extensionBundleId = "com.pangolin.pangolinVpn.PacketTunnel"
// App Group PacketTunnel extension UserDefaults
private let appGroup = "group.com.pangolin.pangolinVpn"
private var statusObserver: NSObjectProtocol?
@@ -99,7 +102,8 @@ class VpnManager: NSObject {
proto.providerBundleIdentifier = extensionBundleId
proto.serverAddress = serverAddress
manager.protocolConfiguration = proto
manager.localizedDescription = "穿山甲 Pangolin VPN"
// 线localizedDescription VPN/
manager.localizedDescription = "Pangolin 加速"
manager.isEnabled = true
manager.saveToPreferences { [weak self] error in
if error == nil { self?.tunnelManager = manager }
@@ -116,6 +120,10 @@ class VpnManager: NSObject {
completion(makeError("VpnManager: tunnelManager not loaded. Call loadFromPreferences first."))
return
}
// App Group UserDefaults PacketTunnel extension
if let shared = UserDefaults(suiteName: appGroup) {
shared.set(configJson, forKey: "lastConfigJson")
}
do {
let options: [String: NSObject] = ["config": configJson as NSString]
try manager.connection.startVPNTunnel(options: options)