Files
pangolin/docs/ios-ipad-support-plan.html
T

147 lines
11 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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 GroupiOS</td><td><code>group.com.pangolin.pangolinVpn</code>(非 macOS 的 <code>&lt;TeamID&gt;.</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(_:)-&gt;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> 真机峰值 &lt; 设备 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>