下载链接:https://github.com/zhengyuliu047-rgb/ChmlFrp-flutter/releases
使用Flutter开发ChmlFrp桌面客户端:从零到一的实践指南
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
前言
最近完成了一个个人项目——为ChmlFrp内网穿透服务开发一个Flutter图形化桌面客户端。这个项目让我深入实践了Flutter桌面端开发的全流程,在此将开发过程中的技术选型、实现细节和遇到的问题记录下来,希望能为对Flutter桌面开发感兴趣的开发者提供一些参考。
一、项目背景与技术选型
1.1 为什么选择Flutter?
在项目启动前,我对比了几个GUI框架选项:
- Electron:成熟但资源占用较高
- Qt:功能强大但学习曲线较陡
- Flutter:一次编写多端部署,UI表现力强
最终选择Flutter 3.0+的主要原因:
- 跨平台潜力:虽然第一期只做Windows端,但未来可轻松扩展到macOS和Linux
- 开发效率:Hot Reload功能极大提升开发效率
- UI表现力:丰富的Material Design组件库,能构建现代化界面
1.2 开发环境配置
# 安装Flutter SDK
flutter channel stable
flutter upgrade
# 启用桌面支持
flutter config --enable-windows-desktop
# 创建项目
flutter create chmlfrp_flutter
二、项目架构设计
2.1 目录结构
chmlfrp_flutter/
├── lib/
│ ├── models/ # 数据模型
│ │ ├── user.dart # 用户模型
│ │ ├── tunnel.dart # 隧道模型
│ │ └── node.dart # 节点模型
│ ├── pages/ # 页面组件
│ │ ├── login_page.dart
│ │ ├── tunnel_page.dart
│ │ └── settings_page.dart
│ ├── services/ # 服务层
│ │ ├── api_service.dart
│ │ ├── storage_service.dart
│ │ └── frpc_service.dart
│ ├── widgets/ # 自定义组件
│ │ ├── tunnel_card.dart
│ │ └── log_viewer.dart
│ └── main.dart # 应用入口
├── windows/
│ └── frpc_integration/ # frpc集成模块
└── pubspec.yaml # 依赖配置
2.2 状态管理方案
采用Provider + MVVM模式管理应用状态:
// lib/models/app_state.dart
class AppState with ChangeNotifier {
User? _currentUser;
List<Tunnel> _tunnels = [];
bool _isLoading = false;
User? get currentUser => _currentUser;
List<Tunnel> get tunnels => _tunnels;
bool get isLoading => _isLoading;
Future<void> login(String username, String password) async {
_isLoading = true;
notifyListeners();
try {
final user = await ApiService.login(username, password);
_currentUser = user;
await StorageService.saveUser(user);
} catch (e) {
rethrow;
} finally {
_isLoading = false;
notifyListeners();
}
}
}
三、核心功能实现
3.1 用户认证模块
// lib/services/api_service.dart
class ApiService {
static const String _baseUrl = 'https://api.chmlfrp.cn';
static Future<User> login(String username, String password) async {
final response = await http.post(
Uri.parse('$_baseUrl/auth/login'),
body: jsonEncode({
'username': username,
'password': password,
}),
headers: {'Content-Type': 'application/json'},
);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
return User.fromJson(data['user']);
} else {
throw Exception('登录失败: ${response.body}');
}
}
}
3.2 隧道管理界面
// lib/pages/tunnel_page.dart
class TunnelPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('隧道管理'),
actions: [
IconButton(
icon: Icon(Icons.add),
onPressed: () => _showCreateDialog(context),
),
],
),
body: Consumer<AppState>(
builder: (context, appState, child) {
if (appState.tunnels.isEmpty) {
return Center(child: Text('暂无隧道,点击右上角+号创建'));
}
return ListView.builder(
itemCount: appState.tunnels.length,
itemBuilder: (context, index) {
final tunnel = appState.tunnels[index];
return TunnelCard(tunnel: tunnel);
},
);
},
),
);
}
}
3.3 frpc进程集成(关键技术点)
这是项目的核心技术难点,需要Flutter与原生进程交互:
// windows/frpc_integration/frpc_manager.cpp
#include <windows.h>
#include <tchar.h>
class FrpcManager {
public:
bool startFrpc(const std::string& configPath) {
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
std::string command = "frpc.exe -c " + configPath;
if (!CreateProcess(
NULL,
const_cast<LPSTR>(command.c_str()),
NULL,
NULL,
FALSE,
CREATE_NO_WINDOW,
NULL,
NULL,
&si,
&pi
)) {
return false;
}
processHandle_ = pi.hProcess;
return true;
}
bool stopFrpc() {
if (processHandle_) {
TerminateProcess(processHandle_, 0);
CloseHandle(processHandle_);
processHandle_ = NULL;
return true;
}
return false;
}
private:
HANDLE processHandle_ = NULL;
};
对应的Flutter平台通道:
// lib/services/frpc_service.dart
class FrpcService {
static const _platform = MethodChannel('com.chmlfrp/frpc');
static Future<bool> startTunnel(String configPath) async {
try {
final result = await _platform.invokeMethod('startFrpc', {
'configPath': configPath,
});
return result as bool;
} on PlatformException catch (e) {
print('启动失败: ${e.message}');
return false;
}
}
static Future<bool> stopTunnel() async {
try {
final result = await _platform.invokeMethod('stopFrpc');
return result as bool;
} on PlatformException catch (e) {
print('停止失败: ${e.message}');
return false;
}
}
}
四、遇到的问题与解决方案
4.1 中文乱码问题
在Windows端开发时,控制台输出中文出现乱码。解决方案:
- 修改系统区域设置(临时方案):
chcp 65001 - 代码层面解决(推荐):
// 在main函数中设置编码 void main() { // Windows控制台编码设置 if (Platform.isWindows) { final currentCodePage = _getConsoleOutputCP(); if (currentCodePage != 65001) { _setConsoleOutputCP(65001); // UTF-8 } } runApp(MyApp()); }
4.2 进程管理权限问题
在Windows上管理frpc进程需要处理UAC权限。解决方案:
<!-- windows/runner/Runner.manifest -->
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="asInvoker"
uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
4.3 日志实时捕获
需要实时捕获frpc进程的输出日志:
// lib/widgets/log_viewer.dart
class LogViewer extends StatefulWidget {
@override
_LogViewerState createState() => _LogViewerState();
}
class _LogViewerState extends State<LogViewer> {
final List<String> _logs = [];
final _scrollController = ScrollController();
@override
void initState() {
super.initState();
_startLogListening();
}
Future<void> _startLogListening() async {
const channel = EventChannel('com.chmlfrp/logs');
channel.receiveBroadcastStream().listen((data) {
setState(() {
_logs.add(data.toString());
if (_logs.length > 1000) _logs.removeAt(0);
// 自动滚动到底部
WidgetsBinding.instance.addPostFrameCallback((_) {
if (_scrollController.hasClients) {
_scrollController.animateTo(
_scrollController.position.maxScrollExtent,
duration: Duration(milliseconds: 300),
curve: Curves.easeOut,
);
}
});
});
});
}
}
五、打包与发布
5.1 生成安装包
# 构建Release版本
flutter build windows --release
# 使用Inno Setup创建安装程序
# 安装脚本示例
[Setup]
AppName=ChmlFrp客户端
AppVersion=1.0.0
DefaultDirName={pf}\ChmlFrp
OutputDir=.\installer
OutputBaseFilename=ChmlFrp_Setup
[Files]
Source: "build\windows\runner\Release\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs
5.2 依赖文件处理
需要将frpc.exe和相关依赖打包到安装程序中:
# 复制frpc可执行文件
cp third_party/frpc/windows_amd64/frpc.exe build/windows/runner/Release/
# 复制运行库
cp third_party/vcredist/*.dll build/windows/runner/Release/
六、项目总结
6.1 技术收获
- Flutter桌面开发:掌握了Flutter在Windows平台的完整开发流程
- 原生交互:深入理解了Platform Channels的工作原理
- 进程管理:学会了在桌面应用中管理外部进程的方法
- 状态管理:实践了Provider在复杂应用中的最佳实践
6.2 性能数据
- 应用启动时间:< 2秒
- 内存占用:~150MB(包含frpc进程)
- UI帧率:稳定60fps
6.3 开源信息
- 项目地址:https://github.com/zhengyuliu047-rgb/ChmlFrp-flutter
- 许可证:GPL-3.0
- 支持平台:Windows 10/11(64位)
七、未来规划
- 多平台支持:扩展macOS和Linux版本
- 功能增强:添加隧道分组、批量操作等功能
- 性能优化:减少内存占用,提升启动速度
- 插件系统:支持第三方插件扩展
结语
通过这个项目,我不仅完成了一个实用的工具,更深入掌握了Flutter桌面开发的各项技术。希望这篇分享能为正在探索Flutter桌面开发的开发者提供有价值的参考。开发过程中遇到的具体问题,欢迎在评论区交流讨论。
相关资源下载:
- Flutter SDK:https://flutter.dev
- Inno Setup:https://jrsoftware.org/isinfo.php
注意事项:
- 开发前请确保已安装Visual Studio 2019+和Windows 10 SDK
- 打包时注意处理UAC权限问题
- 发布前充分测试不同Windows版本的兼容性
如果可以的话来个star吧qwq
应用展示图片:





评论(5)