不少人期待像桌面端工具一樣,精確指定「某個 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 判斷已經夠準,因為這些目的地通常分得開。iOS 做不到的是:同一個 App 裡一部分流量走代理、其餘直連。
說明:本文技術細節參考 Apple 官方開發者文件(Network Extension / Packet Tunnel Provider)與蘋果開發者論壇的官方回覆整理,具體 API 行為以蘋果最新發布的開發者文件為準。
延伸閱讀:規則分流語法詳解 · 網頁打不開的排查步驟