适用条件
本文只说明:Clash Meta 手机端在 Android 上临时换过网络之后,切回常用 Wi-Fi 或常用蜂窝时,怎样把系统 VPN 与本地接口恢复到可预期的稳定配置。适用条件是设备满足 Clash Meta for Android 仓库要求(最低 Android 5.0,建议 7.0 及以上),包名为 com.github.metacubex.clash.meta,用户曾经授权该应用作为 VPN,并且目标是回到常用承载网络上的既有策略,而不是另写一套协议。稳定在这里指:系统再次承认该应用为当前 VPN、本地 TUN 按 Builder 完整建立、网关套接字被保护且不形成环路;不把任何连通结果写成保证。
切回常用网络后先恢复系统侧约束
换网络期间,系统可能已断开 VPN、忘记应用,或改动 always-on。文档给出的停止来源包括:在「设置 > 网络和互联网 > VPN」断开或忘记应用、关闭正在活动连接上的 always-on,以及用户通过应用界面停止服务。忘记之后需要重新走连接请求对话框。因此切回常用网络后,第一步应确认该应用仍在 VPN 列表中、状态栏钥匙图标与快捷设置信息面板能对应一次活动连接,并且服务活动时的不可清除通知还在。
Always-on(Android 7.0 起)由系统在开机后启动服务,应用负责网关隧道。文档要求为此调整行为:不要依赖“用户每次点连接”才能加载参数,而要把配置保存到每次进程启动之间,并用最近一次设置去建立连接;系统按需拉起时,用户未必在场。Android 8.0 及以上在 always-on 断开或无法连接时会显示不可清除通知。若切回常用网络后看到该通知,应先处理系统维持的会话,而不是假定旧 TUN 仍在。若启用“阻止不使用 VPN 的连接”,未走 VPN 的流量会被拦截,设置应用会警告连通前可能没有互联网;切回后要确认该开关与常用环境一致,否则会出现“常用网络本身正常、但应用全部无连接”的表象。
每个用户或工作资料只能有一个活动 VPN。切回前若其他应用抢过当前 VPN,必须再次 VpnService.prepare():已准备则返回 null,否则返回系统授权 Intent。文档要求始终调用该方法,不能沿用切换网络之前的准备结果。
按固定顺序重建本地接口与网关套接字
系统层约束恢复后,按文档顺序重建:prepare() → protect() 隧道套接字 → 连接网关 → Builder 配置 → establish()。addAddress() 至少写入一个地址及掩码,addRoute() 决定哪些目的地址进入 TUN(全部流量需开放路由如 0.0.0.0/0 或 ::/0),addDnsServer() 写入常用环境下应使用的 DNS。这些值通常来自与网关的握手,切回后应使用当前会话提供的参数重新 establish(),而不是沿用上一张网络上的 ParcelFileDescriptor。未准备或权限收回时 establish() 返回 null,应停止并回到授权步骤。
分应用允许列表或拒绝列表必须在建立连接前设置,且不能同时使用两种列表;应用还需已安装才能加入。若常用环境依赖某一组应用走 VPN、其余走系统网络,切回后应在新的 establish() 之前写回同一策略,改列表只能靠新连接。allowBypass() 只能在建立接口时声明,服务启动后不能改;切回后若常用策略不允许旁路,需要一次完整重建而不是热改。protect() 必须保留,避免网关套接字被系统 VPN 吞回。若重建过程中发生 onRevoke(),替代接口已在转发,应关闭套接字与文件描述符后再从头准备。
用文档提供的启停方式对齐状态,以及失败时下一步
仓库记载可向 com.github.kr328.clash.ExternalControlActivity 发送 com.github.metacubex.clash.meta.action.START_CLASH、STOP_CLASH 或 TOGGLE_CLASH 来启动、停止或切换服务。切回常用网络后,宜先让系统 VPN 页与通知处于已知状态,再用这些 action 把服务拉到与常用配置一致的启停状态。Always-on 场景下系统——而不是用户——控制连接,文档要求禁用会与系统抢断开权的界面逻辑,并在每次启动时读取已保存配置。若应用声明不支持 always-on,可在服务元数据中把 android.net.VpnService.SUPPORTS_ALWAYS_ON 设为 false,系统会关闭设置里对应选项;恢复常用配置前应确认该元数据与当前系统开关没有互相排斥。
若切回后仍不稳定:先看 VPN 列表是否被忘记、prepare() 是否再次要求授权;再看 establish() 是否 null、路由与 DNS 是否在本次 Builder 中完整出现、分应用列表是否在连接前写入。系统显示 always-on 无法连接时,按文档等待重连或关闭该选项后再以应用侧启动。常用网络本身不可达时,先恢复该承载网络。不要在替代接口已经转发的情况下,继续使用切换前的 TUN 描述符当作已恢复。
资料: https://developer.android.com/develop/connectivity/vpn https://github.com/MetaCubeX/ClashMetaForAndroid