不少人期待像桌面端工具一样,精确指定"某个 App 走代理,其他 App 直连"。这个诉求在 iOS 上基本无法完整实现,原因不在 Shadowrocket 本身,而在 iOS 系统底层的网络框架设计。这篇文章说明具体限制在哪里,以及 Shadowrocket 实际采用的替代方案。
iOS 不允许第三方 App 像桌面系统那样直接接管网络底层、随意拦截或修改流量。所有需要转发网络流量的 App(包括 Shadowrocket),都必须通过苹果提供的官方框架 Network Extension 来实现,其中负责流量转发的核心组件叫 NEPacketTunnelProvider。这也是为什么首次使用时系统会弹出"VPN 配置"授权提示——这是走官方框架的必经步骤,不是 Shadowrocket 自己发明的机制。
根据苹果官方文档,NEPacketTunnelProvider 只支持两种路由模式,而且是互斥的:
| 模式 | 工作方式 | 限制 |
|---|---|---|
| 按目标 IP 路由 destinationIP | 根据流量要访问的目标地址决定是否进入隧道,Shadowrocket 的全局代理、规则分流用的都是这种模式 | 系统在这个模式下不会告诉 App"这个请求是哪个 App 发出的",只能按域名或 IP 判断,无法感知来源 App |
| 按来源 App 路由 sourceApplication | 系统按流量的来源 App 决定是否转发到你的隧道 | 这种"分应用 VPN"模式一旦某个 App 的流量被路由进隧道,就必须全部由你的 App 处理,不能只处理其中一部分再放一部分直连;且这种模式通常需要 MDM(企业设备管理)配置才能启用,普通用户自己安装的 App 用不到 |
换句话说,苹果的设计里从来就没有"既按 App 区分,又能在同一个 App 内部再分流一部分"这种模式——这不是哪家代理工具没做好,而是系统 API 层面就没有开放这个能力。这一点在苹果开发者论坛的多个官方回复里都有明确说明:「分应用 VPN 模式下,没有机制可以让你只处理某个 App 的部分流量」。
既然系统层面拿不到"这个请求来自哪个 App"这个信息,Shadowrocket 走的是 按目标域名 / IP 判断 的路线:规则文件里写的 DOMAIN-SUFFIX、IP-CIDR、GEOIP 等规则,本质上是在用"这个 App 通常会连接哪些域名或服务器"来近似还原"按 App 分流"的效果,而不是系统真的识别出了发出请求的 App 是谁。
这也解释了几个实际使用中会遇到的现象:
不是。对绝大多数场景(比如"国内网站直连、海外网站走代理")来说,按域名和 IP 段判断已经足够准确,因为国内外网站的域名和服务器归属地本身就是清晰可分的。真正受限的是"同一个 App 内部,一部分流量代理、一部分直连"这种更细粒度的诉求,这才是系统层面无法支持的部分。
说明:本文技术细节参考 Apple 官方开发者文档(Network Extension / Packet Tunnel Provider)与苹果开发者论坛的官方回复整理,具体 API 行为以苹果最新发布的开发者文档为准。
延伸阅读:规则分流语法详解 · 网页打不开的排查步骤