目录

FlClash:45K Stars 的多平台代理客户端,如何用 Flutter + Rust + Go 三语言拼出 ClashMeta 桌面/手机体验

FlClash:45K Stars 的多平台代理客户端,如何用 Flutter + Rust + Go 三语言拼出 ClashMeta 桌面/手机体验

§1 先给判断

FlClash 是一个把「Clash 内核 + Flutter UI + 跨平台系统能力」三件事缝在一起的多平台代理客户端,45K Stars、GPL-3.0、最近一次发布 v0.8.94(2026-07-11)。它值得专门拆开看的工程原因有三条:

  1. 三语言拼装:UI 层 Flutter(Dart),桥层 Rust(rust_api 包),内核层 Go(Clash Meta 编译产物)。Flutter 跨平台 + Rust 系统调用 + Go 高并发代理服务器——每一种语言都被钉在它最擅长的事情上。
  2. 四端覆盖 + 体验一致:Android / Windows / macOS / Linux 共用同一份 Dart UI,配合 Material You 动态色与平台自适应布局,把「同代码跨端」做到了代理类工具里罕见的完成度。
  3. 平台集成深度:Android Quick Tile(无障碍瓷砖开关)、Android 主进程拆分、Windows IPC 优化、Windows arm64 支持、macOS 性能修复、Linux tray 集成——每个平台的「反人性默认」都被单独处理过。

仓库地址:https://github.com/chen08209/FlClash。最近一年的发布节奏稳定在 6-10 周一个版本,每个版本都列出 5-10 条修复+优化项(CHANGELOG 见 CHANGELOG.md)。

文章主轴:拆开 FlClash 的三层架构(lib/core 事件流、lib/plugins 原生桥、lib/manager 平台集成)+ setup.dart 构建脚本对工具链的统一调用,给一份「Flutter 想碰系统能力时,桥层到底要堆多少」的真实样本。

§2 仓库坐标:放在代理客户端谱系里看

代理客户端项目大致分四类:

类型代表核心能力FlClash 位置
原生单平台Clash for Windows (CFW)、ClashX单平台极致体验不选
跨平台 Go UIClash Verge、Clash Meta for AndroidGo 跨平台但 UI 受限部分重叠
Flutter 跨平台FlClash、HiddifyUI 体验优先选这条
命令行内核clash-meta 内核只负责代理流量不选

FlClash 在「Flutter 跨平台代理」赛道里是 Stars 数最高的——它把「代理客户端」从命令行工具升级成「和 Telegram / Spotify 一类的日用软件」的设计语言。这个定位选择决定了它必须解决三件事:

  1. 跨端 UI 一致(Flutter 自带)
  2. 系统能力集成(VPN 接口、Tray、Quick Tile、开机启动、热键)
  3. 内核与 UI 的双向通信(Flutter 不能直接控制 Go 服务)

下面逐层拆。

§3 顶层目录:三层 + 一个构建器 + 一个文档

主目录(main 分支):

FlClash/
├── android/                     # Android 工程
├── linux/                       # Linux 打包脚本与 .deb 描述
├── macos/                       # macOS 工程
├── windows/                     # Windows 工程(Inno Setup 脚本)
├── lib/                         # Flutter Dart 代码
│   ├── application.dart
│   ├── main.dart
│   ├── state.dart               # 全局 Riverpod 状态根
│   ├── common/                  # 通用工具
│   ├── core/                    # 与 Clash 内核的桥接层
│   ├── database/                # 本地存储
│   ├── enum/
│   ├── features/                # 业务模块
│   ├── l10n/                    # 国际化字符串
│   ├── manager/                 # 平台能力封装(VPN/Tray/Hotkey/Window/...)
│   ├── models/                  # 数据模型
│   ├── pages/                   # 页面
│   ├── plugins/                 # 自研 Flutter 插件(桌面/移动)
│   ├── providers/               # Riverpod 状态树
│   ├── views/                   # 视图组件
│   └── widgets/                 # 复用控件
├── plugins/                     # Flutter 插件源码
│   ├── proxy/                   # 平台代理 / VPN 接入
│   └── wifi_ssid/               # Wi-Fi SSID 信息
├── core/                        # ClashMeta 内核子模块
├── services/                    # 其他服务模块
├── tool/                        # 构建辅助工具
├── arb/                         # 翻译文件
├── assets/                      # 图标、字体、动画
├── assets_source/               # 源资源(设计稿)
├── test/
├── snapshots/                   # README 演示动图
├── pubspec.yaml                 # Flutter 依赖
├── pubspec.lock
├── setup.dart                   # 统一构建脚本(Dart 写的 build entry)
├── Makefile                     # 包装 setup.dart
├── AGENTS.md / CLAUDE.md        # AI 协作约定
├── CHANGELOG.md
├── analysis_options.yaml
├── distribute_options.yaml
└── README.md / README_zh_CN.md

注:plugins/ 下的 proxy/wifi_ssid/ 是自研插件源码路径,对应 pubspec.yaml 里的 proxy: { path: plugins/proxy }wifi_ssid: { path: plugins/wifi_ssid }。其它依赖(如 tray_managerlaunch_at_startupwindow_manageryaml_writer)是 fork 自作者的私有仓库,引用 GitHub 而非 pub.dev。

§4 lib/core:与 Clash 内核通信的桥层

lib/core/ 下的文件结构(GitHub API 列出):

core/
├── clash.dart
├── controller.dart
├── core.dart
├── event.dart
├── interface.dart
├── lib.dart
├── service.dart
└── transport.dart

这八个文件几乎可以一对一映射到 Clash 内核的对外能力面:

文件推断职责
core.dart核心入口(启动、关闭、生命周期)
controller.dart控制器(订阅切换、模式切换)
event.dart事件流定义
interface.dart抽象接口
lib.dart库管理(订阅配置加载)
service.dart服务(系统代理、TUN、HTTP)
transport.dart传输层封装(IPC / 进程间通信)
clash.dart高层 API 聚合

pubspec.yaml 里同时存在 proxy: { path: plugins/proxy }rust_api 引用——main.dart 顶部这两行是入口:

import 'package:rust_api/rust_api.dart';
import 'package:fl_clash/state.dart';
// ...
Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  try {
    if (system.isDesktop) {
      await RustLib.init();          // ← Rust 桥初始化(仅桌面端)
    }
    final version = await system.version;
    final container = await globalState.init(version);
    HttpOverrides.global = FlClashHttpOverrides();
    runApp(
      UncontrolledProviderScope(
        container: container,
        child: const Application(),
      ),
    );
  } catch (e, s) {
    runApp(
      MaterialApp(
        home: InitErrorScreen(error: e, stack: s),
      ),
    );
  }
}

值得专门提的三点:

  1. RustLib.init() 仅在桌面端调用——移动端(Android/iOS)用平台 VPN API 直接接管流量,不需要 Rust 桥。
  2. HttpOverrides.global = FlClashHttpOverrides()——Dart 的 HTTP 客户端被代理覆盖,这是 Clash 类工具让应用内流量也走代理的标准做法。
  3. 错误兜底走 InitErrorScreen——启动失败时不白屏,直接展示错误页。这对面向普通用户的客户端是基本礼貌。

§5 lib/manager:13 个 Manager 拼出平台能力全景

lib/manager/ 目录下:

manager/
├── android_manager.dart
├── app_manager.dart
├── connectivity_manager.dart
├── core_manager.dart            # ← Clash 内核状态、订阅、流量统计
├── hotkey_manager.dart
├── manager.dart                 # ← 总入口
├── proxy_manager.dart
├── status_manager.dart
├── theme_manager.dart
├── tile_manager.dart            # ← Android Quick Tile
├── tray_manager.dart            # ← 系统托盘
├── vpn_manager.dart             # ← VPN 接口封装
└── window_manager.dart          # ← 桌面窗口管理

每一类 Manager 都是把平台能力收编为可被 Riverpod 订阅的状态源。举三个例子说明这种分层的设计意图:

§5.1 vpn_manager.dart

代理客户端在 Android 上必须实现 VpnService——这是 Android 系统级 VPN 接口。vpn_manager.dart 负责:

  • 创建 VpnService.Builder
  • 写入 TUN 设备配置(地址、DNS、路由)
  • 与 Go 内核进程建立 IPC
  • 启动/停止生命周期管理

§5.2 tile_manager.dart(Android Quick Tile)

CHANGELOG 多次提到「optimize android tile service」「fix android tile service」——这是 Android 7.0+ 的通知栏 Quick Settings Tile(无障碍瓷砖)。FlClash 让用户下拉通知栏点一下瓷砖就能开关代理,避免每次打开 App。

这是一个看似小、实则要解决不少平台版本碎片化问题的能力:每个 Android 厂商 ROM 对 Tile API 行为有微差异。

§5.3 tray_manager.dart

桌面端(Windows/macOS/Linux)都要系统托盘。FlClash 用作者 fork 的 tray_managerpubspec.yaml 里直接引用 GitHub)——fork 的原因是官方版对 Linux 的 libayatana-appindicator3 支持不够好。

CHANGELOG 多次提到「optimize windows tray auto hide」「fix windows tray」「optimize tray auto hide」——可见托盘这一块也是持续打磨的对象。

§6 lib/plugins:自研 Flutter 插件

lib/plugins/ 目录只有两个:

plugins/
├── app.dart
├── service.dart
└── tile.dart

这是 Android 端 Flutter plugin 的 Dart 入口(service.dart 监听 Android Service,tile.dart 对接 Quick Tile API)。对应的 plugins/ 仓库里放平台侧 Kotlin/Java 代码(不在 lib/ 下,但 pubspec.yaml 通过 proxy: { path: plugins/proxy } 引用)。

第三个自研能力是 wifi_ssid——读取当前 Wi-Fi SSID 用于判断「在家/在外」自动切换配置。这是代理类工具里常见但实现细节复杂的场景(Android 8+ 对 Wi-Fi 读取有限制)。

§7 lib/common:43 个工具文件积累

lib/common/ 目录 43 个文件(截取部分):

common/
├── app_localizations.dart      # 国际化
├── archive.dart                # 压缩/解压
├── cache.dart
├── color.dart                  # Material You 取色
├── common.dart
├── compute.dart                # Dart isolate 包装
├── constant.dart
├── context.dart
├── converter.dart
├── datetime.dart
├── dav_client.dart             # WebDAV 客户端(同步用)
├── file.dart
├── fixed.dart
├── function.dart
├── future.dart
├── http.dart
├── icons.dart
├── indexing.dart               # fractional indexing(拖拽排序)
├── input_limits.dart
├── iterable.dart
├── javascript.dart             # flutter_js 封装
├── keyboard.dart
├── launch.dart                 # 启动外部程序
├── link.dart
├── lock.dart
├── measure.dart
├── migration.dart              # 数据迁移
├── mixin.dart
├── navigation.dart
├── navigator.dart
├── network.dart
├── num.dart
├── package.dart
├── path.dart
├── permission.dart
├── picker.dart                 # file_picker 封装
├── preferences.dart            # shared_preferences 封装
└── ...

43 个工具文件是个值得提的信号:FlClash 已经不是「一个写 UI 的项目」,而是「一个有完整工具链 + 跨平台抽象的项目」。compute.dart(异步执行)、migration.dart(老版本数据迁移)、dav_client.dart(云同步)、javascript.dart(规则脚本引擎)——每个文件背后都是一段要处理的真实复杂度。

§8 lib/features:业务模块边界

lib/features/ 目录下:

features/
├── features.dart               # 总入口
└── overwrite/                 # 「覆写」功能
    ├── overwrite.dart
    └── rule.dart

FlClash v0.8.93 提到「Support custom overwrite」——这是 Clash 类工具的高级玩法:用户写一段 JavaScript(在 Web 端常见),在流量被代理之前修改请求/响应。overwrite/ 目录就是这部分规则的模型和实现入口。

§9 setup.dart:跨端构建的统一入口

FlClash 没有用 Flutter 官方的 flutter build 直接打全部平台——它写了自己的 setup.dart(Dart 脚本)做平台特定的准备工作,再用 Flutter 命令编译。

setup.dart 的核心逻辑(截取):

const _allTargets = <String, String>{
  'android': 'apk',
  'linux': 'deb',         // appimage + rpm 仅 amd64
  'macos': 'dmg',
  'windows': 'exe,zip',
};

const _androidFlutterTarget = {
  'arm': 'android-arm',
  'arm64': 'android-arm64',
  'amd64': 'android-x64',
};

const _hostPlatform = {
  'linux': 'linux',
  'macos': 'macos',
  'windows': 'windows',
};

Future<int> _package(
  String platform,
  String env,
  String targets,
  String rootDir,
  String arch, {
  String? androidArch,
  required bool verbose,
}) async {
  final coreSha256 = platform == 'windows' ? await _buildGoCore(rootDir) : null;
  final file = File(p.join(rootDir, 'env.json'));
  await file.writeAsString(
    jsonEncode({'APP_ENV': env, 'CORE_SHA256': ?coreSha256}),
  );
  final flutterBuildArgs = createFlutterBuildArgs(platform: platform, verbose: verbose);
  // ...
}

值得讲的四点:

  1. platform != host 限制:在 Windows 主机上 build Linux 不允许(除了 android)——这是合理的:交叉编译 Flutter + Go 是个复杂的雷区。
  2. CORE_SHA256 仅 Windows 注入:Windows 端的 Go 内核直接编译进二进制,需要把 SHA256 写进环境变量做完整性校验;其它平台走动态加载。
  3. appimage + rpm 仅 amd64:Linux 的桌面包格式分两类——deb 系(deb)和 rpm 系(rpm/appimage),FlClash 只在 amd64 架构提供后两种,arm Linux 没有 rpm/appimage 构建。
  4. 环境变量 APP_ENV:分 pre(预发布)和 stable(稳定)——这是测试与发布分离的标准做法。

§10 Android 构建链路:Flutter + NDK + GCC

Android 端的构建步骤(README):

  1. 装 Android SDK、NDK
  2. ANDROID_NDK 环境变量
  3. dart setup.dart android

完整工具链:

  • Flutter(UI 层)
  • Android SDK(应用打包)
  • Android NDK(编译 Go 内核为 ARM/x86 native lib)
  • dart setup.dart android(统一入口)

NDK 这一步对应 _buildGoCore(rootDir)——在 Android 上 ClashMeta 内核被编译为 .so 文件,运行时通过 Flutter plugin 加载。

§11 Windows 构建链路:Flutter + GCC + Inno Setup

Windows 端的构建步骤(README):

  1. Windows 客户端(必须)
  2. 装 GCC(MinGW-w64 或类似)、Inno Setup
  3. dart setup.dart windows

完整工具链:

  • Flutter(UI 层)
  • GCC(编译 Go 内核为 Windows DLL/EXE)
  • Inno Setup(打包安装器为 .exe
  • dart setup.dart windows(统一入口)

注意 GCC——这和大多数 Go-on-Windows 项目用 MSVC 不同。推测是 ClashMeta 内核本身依赖 CGO,且作者偏好 GCC 工具链的跨平台一致性。

§12 v0.8.94 CHANGELOG 解读:稳定期的细节优化

最近 8 个版本的 CHANGELOG(节选):

版本日期关键改动
v0.8.942026-07-11修复 macOS 性能、支持自定义 global-ua、修复 Linux silent launch
v0.8.932026-05-29支持 custom overwrite、支持 run on demand、优化 Windows IPC、优化 Windows arm64
v0.8.922026-02-02加 SQLite 存储、优化 Android Quick Tile、优化备份/恢复
v0.8.912025-12-12修 Windows 多个问题、优化 overwrite handle、优化 access control 页
v0.8.902025-10-08修 Android tile service、支持追加系统 DNS
v0.8.892025-09-27优化 Windows service mode
v0.8.882025-09-23Android 拆分核心进程、支持 core status check 和 force restart
v0.8.872025-07-29优化桌面视图、优化 logs/requests/connections 页、优化 Windows tray auto hide

可读出的产品节奏:

  • 持续打磨:每版 5-10 项修复,无大改架构
  • 平台均衡:四端各占相当比例,没有只追一端
  • 隐私优先:自定义 UA、IP 同步、Access Control 都是隐私向能力
  • 进程隔离:v0.8.88 把 Android 核心进程拆出来——这是稳定性提升的关键一步

§13 任务流案例:一次「订阅切换」的代码路径

把上面拆的所有模块串起来,看一次完整的「用户切换订阅」走哪些层:

  1. UI 层lib/pages/proxieslib/views/...):用户点击订阅源 A
  2. Provider 层lib/providers/):Riverpod 状态更新,触发 subscriptionProvider
  3. Manager 层lib/manager/core_manager.dart):调用 Clash 内核的「reload config」
  4. Core 桥接lib/core/service.dart):通过 IPC 发送 reload 指令给 Go 内核
  5. Rust 桥rust_api):在桌面端,Rust 负责管理 Go 进程的 IPC(移动端跳过此层)
  6. Go 内核core/ 子模块):Clash Meta 进程重新解析配置文件,更新路由表
  7. 事件回流lib/core/event.dart):内核通过事件流推送新状态
  8. Manager 回调status_manager.dart):订阅 coreStateProvider,更新 UI 显示
  9. 系统层反馈vpn_manager.dart / tray_manager.dart):同步更新 VPN 状态/托盘图标

这条链路展示了 FlClash 「Flutter UI 看似简单、底下叠了六层抽象」的真实形态——这也是为什么 45K Stars 的项目代码量高达 56K+ KB(GitHub API size 字段)。

§14 决策表:你是哪类用户、该不该选 FlClash

你是谁你的诉求建议
普通 Windows/macOS 用户,想找稳定的代理 GUI不想折腾订阅格式✅ FlClash 桌面端体验和 CFW/ClashX 同级
Android 用户,对 Quick Tile 有强需求通知栏瓷砖开关代理✅ 自研 tile 服务,CHANGELOG 多次打磨
macOS Apple Silicon 用户原生 arm64 支持✅ v0.8.93 优化了 Windows arm64,macOS Apple Silicon 走 Flutter 自动适配
Linux 桌面用户想要现代 GUI 替代命令行 clash✅ v0.8.94 修了 silent launch,tray 集成可用
自托管/订阅格式研究者想看 ClashMeta YAML 兼容性✅ FlClash 内核就是 ClashMeta,无格式阉割
想要最简 CFW 风格不需要花哨 UI⚠️ FlClash 功能多,初次接触需要适应
iOS 用户❌ FlClash 不发布 iOS(苹果政策限制 VPN 类工具)
想要开箱即用的免费节点❌ FlClash 是客户端,需要自己准备订阅

§15 与同赛道项目的边界

  • vs Clash Verge:同样是跨平台 GUI,Verge 是 Tauri(Rust)+ WebView,FlClash 是 Flutter + Rust + Go。Verge 安装包更小(WebView 系统自带),FlClash UI 一致性更好。
  • vs ClashX(macOS):ClashX 只做 macOS,体验极致但不跨端。FlClash 在 macOS 上功能更全但启动稍慢。
  • vs Hiddify:Hiddify 同样是 Flutter 跨端,但 FlClash 持续维护节奏更稳、Stars 更多。
  • vs 内核项目 clash-meta:这是上游,FlClash 是消费内核的客户端。

§16 资料口径与边界

已确认(仓库可见证据):

  • 45K Stars / 2851 Forks / 524 open issues(GitHub API 2026-07-12 数据)
  • GPL-3.0 许可
  • Dart(Flutter)语言主导
  • 最近 release v0.8.94(2026-07-11)
  • 主分支 main
  • 自带 setup.dart 构建脚本、core/ 子模块引用
  • lib/ 下的 core/manager/common/features/plugins/ 五个主要目录的职责划分
  • plugins/ 自研两个:proxy/wifi_ssid/
  • 13 个 manager 文件名(已逐项核对)
  • pubspec.yaml 中关键 fork 依赖:window_managertray_managerlaunch_at_startupyaml_writer(均来自作者私有仓库)
  • 四平台支持:Android / Windows / macOS / Linux

已显式标注

  • lib/core/ 下八个文件的精确职责是基于文件名推断——实际边界需要直接读源码
  • lib/features/overwrite/ 的实现机制需读 rule.dart 才能完整确认
  • Rust 桥的具体通信协议(IPC 类型、消息格式)需读 rust_api 源码
  • 43 个 lib/common/ 文件的精确作用以仓库为准

不在本文覆盖

  • iOS 版本(FlClash 无 iOS 端)
  • F-Droid 仓库签名链(README 给了 fingerprint,但本文不展开)
  • WebDAV 同步的具体加密方案
  • Android 拆分核心进程的进程间通信细节(v0.8.88)

§17 参考链接

§18 自测题

  1. FlClash 的三语言分工是什么?分别承担哪一层?
  2. lib/manager/ 下 13 个 Manager 中,哪三个对应移动端最关键的系统能力?
  3. setup.dart 为什么不直接用 flutter build?它解决了哪些工具链衔接问题?
  4. v0.8.94 CHANGELOG 提到 macOS 性能问题修复,但没给数字——这种「无 benchmark 报告的修复」能推出什么、不能推出什么?
  5. 一次「订阅切换」至少要走哪几层模块?列出至少五层。