147 lines
11 KiB
HTML
147 lines
11 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>iOS + iPad 支持 实施计划 — Pangolin</title>
|
||
<style>
|
||
:root{
|
||
--bg:#0f1117; --panel:#171a22; --panel2:#1d2129; --fg:#e6e8ee; --fg2:#a8afbd;
|
||
--accent:#e0884f; --accent2:#5fb0c9; --ok:#5ec27a; --bad:#e06a6a; --warn:#e0b84f;
|
||
--border:#272c36; --mono:"SF Mono",ui-monospace,Menlo,Consolas,monospace;
|
||
--sans:-apple-system,"PingFang SC","Helvetica Neue",Arial,sans-serif;
|
||
}
|
||
*{box-sizing:border-box}
|
||
body{margin:0;background:var(--bg);color:var(--fg);font-family:var(--sans);line-height:1.7;font-size:15px}
|
||
.wrap{max-width:920px;margin:0 auto;padding:48px 24px 96px}
|
||
h1{font-size:30px;line-height:1.3;margin:0 0 8px;letter-spacing:-.01em}
|
||
.sub{color:var(--fg2);font-size:15px;margin:0 0 32px}
|
||
h2{font-size:21px;margin:48px 0 14px;padding-bottom:8px;border-bottom:1px solid var(--border)}
|
||
h3{font-size:16px;margin:28px 0 8px;color:var(--accent2)}
|
||
p{margin:10px 0}
|
||
code{font-family:var(--mono);font-size:.88em;background:var(--panel2);padding:1px 6px;border-radius:5px;color:#f0d9c4}
|
||
pre{background:#0a0c11;border:1px solid var(--border);border-radius:10px;padding:14px 16px;overflow-x:auto;font-family:var(--mono);font-size:13px;line-height:1.55;color:#cdd3df}
|
||
.tag{display:inline-block;font-size:12px;font-weight:600;padding:2px 9px;border-radius:999px;vertical-align:middle}
|
||
.tag.bad{background:rgba(224,106,106,.16);color:var(--bad)}
|
||
.tag.ok{background:rgba(94,194,122,.16);color:var(--ok)}
|
||
.tag.warn{background:rgba(224,184,79,.16);color:var(--warn)}
|
||
.tag.info{background:rgba(95,176,201,.16);color:var(--accent2)}
|
||
.card{background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:18px 20px;margin:16px 0}
|
||
.card.root{border-left:3px solid var(--accent)}
|
||
.card.risk{border-left:3px solid var(--bad)}
|
||
.card h3{margin-top:0}
|
||
table{width:100%;border-collapse:collapse;margin:16px 0;font-size:14px}
|
||
th,td{text-align:left;padding:9px 12px;border-bottom:1px solid var(--border);vertical-align:top}
|
||
th{color:var(--fg2);font-weight:600;font-size:13px}
|
||
td code{font-size:.85em}
|
||
.ok-c{color:var(--ok)} .bad-c{color:var(--bad)} .warn-c{color:var(--warn)}
|
||
ul,ol{padding-left:22px;margin:10px 0}
|
||
li{margin:5px 0}
|
||
.lead{background:linear-gradient(180deg,rgba(224,136,79,.10),transparent);border:1px solid var(--border);border-radius:12px;padding:18px 20px;margin:0 0 8px}
|
||
.small{color:var(--fg2);font-size:13px}
|
||
hr{border:none;border-top:1px solid var(--border);margin:40px 0}
|
||
a{color:var(--accent2)}
|
||
.phase{display:inline-block;font-size:12px;font-weight:700;color:var(--accent);letter-spacing:.04em}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="wrap">
|
||
|
||
<h1>iOS + iPad 支持 实施计划</h1>
|
||
<p class="sub">阅读版(HTML)· 里程碑 <span class="tag info">TestFlight 公测</span> · 分支 <code>feature/pangolin-ios</code> · 2026-06-22</p>
|
||
|
||
<div class="lead">
|
||
<p style="margin:0"><strong>这是阅读版。</strong>执行真相源是同内容的 <code>docs/superpowers/plans/2026-06-22-ios-ipad-support.md</code>(含 <code>- [ ]</code> checkbox,供 <code>executing-plans</code>/<code>subagent-driven-development</code> 驱动逐步执行)。本 HTML 仅供浏览,<strong>勾选/执行以 .md 为准</strong>。</p>
|
||
</div>
|
||
|
||
<p><strong>Goal:</strong>把 iOS 隧道从「能编译的 M3 PoC 桩」推进到「iPhone/iPad 真机真正连通、扛得住 NE 内存红线、可推 TestFlight」,iPad 共用同一 iOS target 并完成布局+横屏适配。</p>
|
||
<p><strong>Architecture:</strong>iOS PacketTunnel 扩展按 macOS 已验证的 libbox 集成方式重写(<code>LibboxNewCommandServer</code> + <code>LibboxPlatformInterfaceProtocol</code> + 真 utun fd),删除 PoC 的 socketpair 手工桥接;主 App 侧 <code>VpnManager</code> 已基本可用,仅需对齐配置 key。iPad 复用已有 <code>form_factor.dart</code>(宽≥600 自动走 <code>TabletShell</code>)。</p>
|
||
|
||
<h2>Global Constraints(每个任务隐含包含)</h2>
|
||
<table>
|
||
<tr><th>项</th><th>值</th></tr>
|
||
<tr><td>sing-box 版本</td><td><code>v1.13.13</code>(与节点对齐)</td></tr>
|
||
<tr><td>TeamID</td><td><code>BYL4KQHMTN</code></td></tr>
|
||
<tr><td>Bundle ID</td><td>主 App <code>com.pangolin.pangolinVpn</code> / 扩展 <code>….PacketTunnel</code></td></tr>
|
||
<tr><td>App Group(iOS)</td><td><code>group.com.pangolin.pangolinVpn</code>(非 macOS 的 <code><TeamID>.</code> 前缀)</td></tr>
|
||
<tr><td>扩展链接铁律</td><td>Libbox <strong>只 Link 不 Embed</strong>;<code>OTHER_LDFLAGS=""</code>;<code>otool -L</code> 零外部 <code>@rpath</code></td></tr>
|
||
<tr><td>libbox 铁律</td><td>后台队列启;非空 <code>LibboxOverrideOptions()</code>;阻塞式 <code>startDefaultInterfaceMonitor</code></td></tr>
|
||
<tr><td>配置来源</td><td>服务端 <code>BuildClientConfig</code> 渲染原样下发;DNS 劫持首条规则(服务端已处理)</td></tr>
|
||
<tr><td>红线词</td><td>用户可见文案禁 VPN/翻墙/科学上网,用「加速」口径</td></tr>
|
||
<tr><td>内存红线</td><td>NE 进程 ~50MB(旧设备 ~15MB)— 头号风险</td></tr>
|
||
<tr><td>平台</td><td>iOS 12+,设备族 <code>"1,2"</code></td></tr>
|
||
</table>
|
||
|
||
<h2>File Structure</h2>
|
||
<table>
|
||
<tr><th>文件</th><th>责任</th><th>动作</th></tr>
|
||
<tr><td><code>client/ios/Frameworks/Libbox.xcframework</code></td><td>iOS+sim libbox 静态框架</td><td>构建产物放入(不入 git)</td></tr>
|
||
<tr><td><code>client/ios/.gitignore</code></td><td>排除框架产物</td><td>追加一行</td></tr>
|
||
<tr><td><code>client/ios/Runner.xcodeproj/project.pbxproj</code></td><td>扩展链接、Team、OTHER_LDFLAGS</td><td>Xcode 改</td></tr>
|
||
<tr><td><code>client/ios/PacketTunnel/PacketTunnelProvider.swift</code></td><td>NE 扩展 libbox 集成</td><td>重写对齐 macOS</td></tr>
|
||
<tr><td><code>client/ios/Runner/VpnManager.swift</code></td><td>主 App 隧道控制</td><td>核对(配置 key 已是 config)</td></tr>
|
||
<tr><td><code>client/ios/Runner/Info.plist</code></td><td>iPad orientation + 导出合规</td><td>改</td></tr>
|
||
<tr><td><code>client/test/responsive/form_factor_test.dart</code></td><td>断点判定测试</td><td>新建</td></tr>
|
||
</table>
|
||
<p class="small">参照(只读):<code>client/macos/PacketTunnel/PacketTunnelProvider.swift</code>(金标准)、<code>client/lib/core/responsive/form_factor.dart</code>、<code>client/lib/shell/tablet_shell.dart</code>。</p>
|
||
|
||
<h2>任务分阶段</h2>
|
||
|
||
<div class="card root">
|
||
<h3><span class="phase">PHASE A</span> · libbox iOS 框架(解阻塞)</h3>
|
||
<p><strong>Task A1</strong>:跑 <code>bash scripts/build-libbox.sh apple</code>(不带 platform)→ 产出含 <code>ios-arm64</code>+<code>ios-arm64_x86_64-simulator</code> 切片的 xcframework → 拷入 <code>client/ios/Frameworks/</code> → <code>.gitignore</code> 追加 <code>**/Frameworks/Libbox.xcframework/</code>。macOS 既有框架不动。</p>
|
||
</div>
|
||
|
||
<div class="card root">
|
||
<h3><span class="phase">PHASE B</span> · Xcode 接线与签名</h3>
|
||
<p><strong>Task B1</strong>:照 macOS 扩展把 <code>Libbox + NetworkExtension + SystemConfiguration + libresolv.tbd</code> <strong>只 Link 不 Embed</strong>(AppKit 换掉);扩展 <code>OTHER_LDFLAGS=""</code>;两 target <code>DEVELOPMENT_TEAM=BYL4KQHMTN</code>;确认 App Groups + Network Extensions 能力。验证:<code>flutter build ios --no-codesign</code> 通过 + <code>otool -L</code> 扩展二进制零外部 <code>@rpath</code>。</p>
|
||
</div>
|
||
|
||
<div class="card root">
|
||
<h3><span class="phase">PHASE C</span> · iOS Provider 重写(对齐 macOS)</h3>
|
||
<p><strong>Task C1(最大的活)</strong>:现有 iOS 桩用的是真实框架里<strong>不存在的旧 API</strong>(<code>LibboxNewService</code>/<code>openTun(_:)->Int32</code>/socketpair 桥接),链入真实 Libbox 后编不过。以 macOS 金标准整体替换,仅改三处 + 接内存监控:</p>
|
||
<ul>
|
||
<li>常量:<code>appGroup="group.com.pangolin.pangolinVpn"</code>、log subsystem 改 iOS bundle</li>
|
||
<li><code>resolveConfig</code> 读 <code>options["config"]</code>(对齐 VpnManager)+ App Group <code>lastConfigJson</code> 回退</li>
|
||
<li>接 <code>MemoryMonitor</code>(start/stop/sleep/wake);<code>handleAppMessage</code> 仅留 <code>getStatus</code>/<code>getMemory</code></li>
|
||
<li><code>PangolinPlatformInterface</code>/<code>InterfaceIterator</code>/<code>simpleError</code> 原样照搬(iOS 全 API 可用)</li>
|
||
</ul>
|
||
<p class="small">验证:<code>flutter build ios</code> 通过;grep 命中 后台队列 / 非空 OverrideOptions / 阻塞 interface monitor / config key 四项。</p>
|
||
</div>
|
||
|
||
<div class="card risk">
|
||
<h3><span class="phase">PHASE D</span> · 真机连通与内存验收(含头号风险闸门)</h3>
|
||
<p><strong>Task D1</strong>:iPhone 真机 <code>flutter run --release</code> → 点连接 → device console 看 <code>startTunnel: service started</code>、无 <code>no available network interface</code>/无 SIGSEGV → Safari 验出网 → 10 分钟读 <code>peakRssBytes</code>。</p>
|
||
<p><strong>Task D2(仅当内存超限触发)</strong>:本地 <code>.srs</code> 预取瘦身——把 <code>geoip-cn.srs</code>/<code>geosite-cn.srs</code> 打进 app bundle、启动期拷到 App Group 容器、服务端 <code>clientconfig.go</code> rule_set 由 <code>remote</code> 改 <code>local</code>,避免启动期下载进 NE 内存。</p>
|
||
<p class="small">⚠️ TestFlight 推送以「内存实测通过」为前置闸门。</p>
|
||
</div>
|
||
|
||
<div class="card root">
|
||
<h3><span class="phase">PHASE E</span> · iPad UI 适配(布局 + 横屏)</h3>
|
||
<p><strong>Task E1</strong>:<code>form_factor_test.dart</code> widget 测试锁定 iPad 竖(768)/横(1024) → tablet、iPhone(390) → mobile。</p>
|
||
<p><strong>Task E2</strong>:<code>Info.plist</code> 开 iPad 全向 <code>UISupportedInterfaceOrientations~ipad</code>;iPad 模拟器逐屏竖/横目测对照 <code>design/ui_kits/tablet</code> 原型,无溢出/不空旷;<code>flutter analyze</code> 过。</p>
|
||
<p><strong>Task E3</strong>:iPad 真机连通 + 横竖屏布局验收。</p>
|
||
</div>
|
||
|
||
<div class="card root">
|
||
<h3><span class="phase">PHASE F</span> · 分发到 TestFlight</h3>
|
||
<p><strong>Task F1(用户在后台手点)</strong>:注册两个 App ID(勾 App Groups + Network Extensions)、建 App Group <code>group.com.pangolin.pangolinVpn</code>、描述文件、App Store Connect 建 app 记录。</p>
|
||
<p><strong>Task F2</strong>:<code>Info.plist</code> 加 <code>ITSAppUsesNonExemptEncryption</code>;递增构建号;<code>flutter build ipa --release</code>;<code>xcrun altool</code>/Transporter 上传 TestFlight。</p>
|
||
</div>
|
||
|
||
<h2>验收标准(DoD)</h2>
|
||
<ol>
|
||
<li>Libbox 含 iOS 切片;扩展 <code>otool -L</code> 零外部 <code>@rpath</code>。</li>
|
||
<li>iPhone 真机:连接 → sing-box 起来 → 打开境外站点。</li>
|
||
<li>iPad 真机:连通 + 竖/横屏布局对照原型无拉伸/空旷。</li>
|
||
<li><code>MemoryMonitor</code> 真机峰值 < 设备 jetsam 上限,10 分钟不被杀。</li>
|
||
<li>成功 Archive 并上传 TestFlight,外部测试者可装可连。</li>
|
||
</ol>
|
||
|
||
<hr>
|
||
<p class="small">执行真相源:<code>docs/superpowers/plans/2026-06-22-ios-ipad-support.md</code> · 设计稿:<a href="ios-ipad-support-design.html">ios-ipad-support-design.html</a> · 索引:<a href="index.html">docs/index.html</a></p>
|
||
|
||
</div>
|
||
</body>
|
||
</html>
|