Flutter 桌面 MacOS:如何使用 Flutter 应用程序从 Finder 打开文件

问题描述 投票:0回答:2

我编写了一个 Flutter 桌面 MacOS 应用程序,它使用命令行参数来处理文件:

void main(List<String> args) async {
  if (args.isNotEmpty) {
    runApp(MyApp(args.first))
  } else ...;
}

当我从 shell 运行它时,它按预期工作:

# this command is ok:
/Applications/TommyView.app/Contents/MacOS/TommyView Pictures/hey.png

但是当我将此应用程序分配给所有 *.png 图像,并想从 Finder 运行它时,它显示:

(或者有时会出现另一个错误,具体取决于 Info.plist:

TommyView cannot open files in the “PNG image” format.

我还注意到执行到了

"else"
情况(即
args
为空)。

我想 Info.plist 中缺少一些魔法。请大家帮忙解答一下。

flutter macos info.plist flutter-desktop
2个回答
0
投票

您需要在 Info.plist 中使用

CFBundleDocumentTypes
声明应用程序处理的文件类型。

更重要的是,命令行参数并不是应用程序接收要在 macOS 上打开的文件的方式,因此 Dart 代码将无法工作。要处理文件,您需要在 macOS Runner 中实现

application(_:openFile:)
(可以随时调用,而不仅仅是在启动时调用),然后使用 平台通道将文件传递给 Dart。


0
投票

谢谢@smorgan,您的回复。让我通过为其他 Flutter 开发人员添加一段代码来改进您的答案:

  1. MainFlutterWindow.swift
    添加以下内容:
class MainFlutterWindow: NSWindow {
    open var currentFile: String? // add this variable

  override func awakeFromNib() {
    ...

    // interop with Flutter
    let channel = FlutterMethodChannel(name: "myChannel", binaryMessenger: flutterViewController.engine.binaryMessenger)
    channel.setMethodCallHandler({
        (call: FlutterMethodCall, result: FlutterResult) -> Void in
        if (call.method == "getCurrentFile") {
            result(self.currentFile)
        } else {
            result(FlutterMethodNotImplemented)
        }
    })
    ...
  }
}
  1. AppDelegate.swift
    中你需要处理
    openFile
@NSApplicationMain
class AppDelegate: FlutterAppDelegate {
    ...
    // called when a user double-clicks on a file in Finder
    //override func application(_ sender: NSApplication, openFile filename: String) -> Bool {
        //(mainFlutterWindow as! MainFlutterWindow).currentFile = filename
      //return true
    //}

    // update 2024:
    override func application(_ application: NSApplication, open urls: [URL]) {
      if (!urls.isEmpty) {
        (mainFlutterWindow as! MainFlutterWindow).currentFile = urls.first!.path
      }
    }
}
  1. 现在在你的
    main.dart
void main(List<String> args) async {
  WidgetsFlutterBinding.ensureInitialized();
  final startFile = await getStartFile(args);
  runApp(MyApp(startFile));
}

Future<String> getStartFile(List<String> args) async {
  if (args.isNotEmpty) return args.first;
  if (Platform.isMacOS) {
    // in MacOS, we need to make a call to Swift native code to check if a file has been opened with our App
    const hostApi = MethodChannel("myChannel");
    final String? currentFile = await hostApi.invokeMethod("getCurrentFile");
    if (currentFile != null) return currentFile;
  }
  return "";
}
  1. [可选]向
    Info.plist
    添加文件扩展名,使其在 MacOS 推荐的应用程序中“可见”:
<dict>
    ...
    <key>CFBundleDocumentTypes</key>
    <array>
        <dict>
            <key>CFBundleTypeExtensions</key>
            <array>
                <string>jpg</string>
                <string>jpeg</string>
                <string>png</string>
                <string>gif</string>
                <string>webp</string>
                <string>bmp</string>
                <string>wbmp</string>
            </array>
            <key>CFBundleTypeRole</key>
            <string>Viewer</string>
        </dict>
    </array>

希望对你有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.