Shadowrocket 博客 · 原理科普

为什么 Shadowrocket 做不到
「只让某个 App 走代理」。

不少人期待像桌面端工具一样,精确指定"某个 App 走代理,其他 App 直连"。这个诉求在 iOS 上基本无法完整实现,原因不在 Shadowrocket 本身,而在 iOS 系统底层的网络框架设计。这篇文章说明具体限制在哪里,以及 Shadowrocket 实际采用的替代方案。

iOS 上的 VPN,走的是苹果自己的框架

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 的部分流量」。

Shadowrocket 实际采用的替代方案

既然系统层面拿不到"这个请求来自哪个 App"这个信息,Shadowrocket 走的是 按目标域名 / IP 判断 的路线:规则文件里写的 DOMAIN-SUFFIXIP-CIDRGEOIP 等规则,本质上是在用"这个 App 通常会连接哪些域名或服务器"来近似还原"按 App 分流"的效果,而不是系统真的识别出了发出请求的 App 是谁。

这也解释了几个实际使用中会遇到的现象:

这是不是意味着规则分流没有意义?

不是。对绝大多数场景(比如"国内网站直连、海外网站走代理")来说,按域名和 IP 段判断已经足够准确,因为国内外网站的域名和服务器归属地本身就是清晰可分的。真正受限的是"同一个 App 内部,一部分流量代理、一部分直连"这种更细粒度的诉求,这才是系统层面无法支持的部分。

说明:本文技术细节参考 Apple 官方开发者文档(Network Extension / Packet Tunnel Provider)与苹果开发者论坛的官方回复整理,具体 API 行为以苹果最新发布的开发者文档为准。

了解原理之后,实际配起来更快 知道了限制在哪里,规则文件该怎么写、什么时候该用全局代理会更容易判断
前往下载 →

延伸阅读:规则分流语法详解 · 网页打不开的排查步骤