Flutter Windows桌面应用如何获取“Open with”打开的文件列表?
Flutter Windows桌面应用获取“Open with”打开的文件列表
在Windows平台上,用户通过“Open with”选择你的应用打开文件、或双击关联格式文件时,系统会通过命令行参数传递文件路径;如果应用已在运行,还需要通过Windows消息机制接收新的文件路径。以下是具体实现方式:
一、获取启动时的文件路径
应用首次启动时,系统会将待打开的文件路径作为命令行参数传递给应用。你可以通过dart:io的Platform类读取这些参数:
import 'dart:io'; import 'package:flutter/material.dart'; void main() { // 过滤掉应用自身路径,剩下的就是待打开的文件路径 final List<String> rawArgs = Platform.args; final List<String> targetFiles = rawArgs.length > 1 ? rawArgs.sublist(1).where((path) => File(path).existsSync()).toList() : []; runApp(MyApp(openedFiles: targetFiles)); } class MyApp extends StatelessWidget { final List<String> openedFiles; const MyApp({super.key, required this.openedFiles}); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: const Text('已打开文件')), body: openedFiles.isEmpty ? const Center(child: Text('暂无打开的文件')) : ListView.builder( itemCount: openedFiles.length, itemBuilder: (_, index) => ListTile(title: Text(openedFiles[index])), ), ), ); } }
二、处理应用已启动时的新文件
如果应用已经在运行,用户再次通过“Open with”打开文件,默认会启动新的应用实例。要让已有实例接收新文件,需要做两件事:
- 实现单实例应用,避免重复启动
- 通过Windows的
WM_COPYDATA消息传递文件路径
1. 添加依赖
在pubspec.yaml中引入win32包,用于调用Windows原生API:
dependencies: flutter: sdk: flutter win32: ^5.0.0 # 使用最新稳定版本
2. 实现单实例与消息监听
import 'dart:ffi'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart'; import 'package:win32/win32.dart'; // 全局存储所有打开的文件 final List<String> allOpenedFiles = []; // 互斥量名称,确保单实例 const _mutexName = 'com.yourcompany.yourapp.singleinstance'; void main() { // 处理启动参数 final rawArgs = Platform.args; final launchFiles = rawArgs.length > 1 ? rawArgs.sublist(1).where((p) => File(p).existsSync()).toList() : []; allOpenedFiles.addAll(launchFiles); if (Platform.isWindows) { // 检查是否已有实例 final mutex = CreateMutex(nullptr, TRUE, TEXT(_mutexName)); final error = GetLastError(); if (error == ERROR_ALREADY_EXISTS) { // 已有实例,发送文件路径并退出当前实例 _sendFilesToExistingInstance(launchFiles); exit(0); } // 注册窗口消息处理器 _registerWindowMessageHandler(); } runApp(const MyApp()); } // 向已有实例发送文件路径 void _sendFilesToExistingInstance(List<String> files) { if (files.isEmpty) return; // 拼接文件路径(用换行分隔,避免空格问题) final data = files.join('\n'); // 查找已有窗口(这里需要根据你的应用窗口标题或类名调整) final hwnd = FindWindow(nullptr, TEXT('你的应用窗口标题')); if (hwnd != nullptr) { final copyData = COPYDATASTRUCT( dwData: 0, cbData: (data.length * 2 + 2).cast<DWORD>(), lpData: data.toNativeUtf16().cast(), ); SendMessage(hwnd, WM_COPYDATA, nullptr, copyData.addressOf.cast<LPARAM>()); } } // 注册窗口消息处理 void _registerWindowMessageHandler() { final hwnd = GetForegroundWindow(); // 获取当前应用窗口句柄,实际可根据情况调整 SetWindowLongPtr(hwnd, GWLP_WNDPROC, Pointer.fromFunction(_windowProc, 0)); } // 窗口消息回调 LRESULT _windowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if (uMsg == WM_COPYDATA) { final pCopyData = lParam.cast<COPYDATASTRUCT>(); final data = pCopyData.ref.lpData.cast<Utf16>().toDartString(); // 解析传递的文件路径 final newFiles = data.split('\n').where((p) => p.isNotEmpty && File(p).existsSync()).toList(); if (newFiles.isNotEmpty) { allOpenedFiles.addAll(newFiles); // 通知UI更新,可使用Provider、ValueNotifier等状态管理方式 if (kDebugMode) print('新增打开文件:$newFiles'); } return TRUE; } return DefWindowProc(hwnd, uMsg, wParam, lParam); } class MyApp extends StatefulWidget { const MyApp({super.key}); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { // 使用ValueNotifier监听文件列表变化,更新UI final ValueNotifier<List<String>> _filesNotifier = ValueNotifier(allOpenedFiles); @override void initState() { super.initState(); // 可以在这里添加监听,比如全局通知更新文件列表 } @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: const Text('已打开文件')), body: ValueListenableBuilder<List<String>>( valueListenable: _filesNotifier, builder: (_, files, __) => files.isEmpty ? const Center(child: Text('暂无打开的文件')) : ListView.builder( itemCount: files.length, itemBuilder: (_, index) => ListTile(title: Text(files[index])), ), ), ), ); } }
三、配置文件关联(可选)
要让系统识别你的应用可以打开特定格式的文件,在pubspec.yaml的windows配置中添加文件关联:
flutter: windows: file_associations: - extension: txt description: 文本文件 mime_type: text/plain - extension: md description: Markdown文档 mime_type: text/markdown
执行flutter build windows打包后,安装程序会自动配置Windows注册表,用户双击对应格式文件时会默认用你的应用打开。
关键注意事项
- 带空格的文件路径:命令行参数中带空格的路径会被自动包裹引号,
Platform.args会正确解析为单个参数,无需手动处理。 - 窗口句柄获取:示例中用
GetForegroundWindow()获取窗口句柄,实际开发中可以通过flutter_window_manager包或win32的FindWindow根据窗口类名/标题精准获取。 - 状态管理:当新增文件时,需要通过状态管理工具(如ValueNotifier、Provider)通知UI更新,避免视图不刷新。
内容的提问来源于stack exchange,提问作者mirkaim
相关产品推荐
相关产品推荐

