Add basic file writing for macos

This commit is contained in:
2024-01-23 17:17:23 +08:00
parent 24fe2c751c
commit bf76de0f5a
4 changed files with 137 additions and 4 deletions

View File

@@ -74,7 +74,7 @@
33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = "<group>"; };
33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = "<group>"; };
33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = "<group>"; tabWidth = 2; };
33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = "<group>"; };
33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = "<group>"; };
33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = "<group>"; };
@@ -195,7 +195,6 @@
6A4FDD73E68B92DC94675AC0 /* Pods-RunnerTests.release.xcconfig */,
0311B7E1884E9DFE7BD27E00 /* Pods-RunnerTests.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
@@ -575,6 +574,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
};
@@ -701,6 +701,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
@@ -721,6 +722,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
};

View File

@@ -10,5 +10,7 @@
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
</dict>
</plist>

View File

@@ -1,5 +1,53 @@
import Cocoa
import FlutterMacOS
import Foundation
import System
import UniformTypeIdentifiers
func extFromMimetype(mimeType: String) -> String? {
switch (mimeType) {
case "image/jpeg":
return ".jpg"
case "image/png":
return ".png"
case "image/webp":
return ".webp"
case "application/zip":
return ".zip"
default:
return nil
}
}
func openFile(result: FlutterResult, fn: String, readOnly: Bool, writeOnly: Bool, append: Bool) {
let mode = if readOnly && writeOnly {
FileDescriptor.AccessMode.readWrite
} else if readOnly {
FileDescriptor.AccessMode.readOnly
} else if writeOnly {
FileDescriptor.AccessMode.writeOnly
} else {
FileDescriptor.AccessMode.readWrite
}
var opts = FileDescriptor.OpenOptions.init()
if writeOnly {
opts.insert(FileDescriptor.OpenOptions.create)
if !readOnly {
opts.insert(FileDescriptor.OpenOptions.truncate)
}
}
if append {
opts.insert(FileDescriptor.OpenOptions.append)
}
let permissions = FilePermissions(rawValue: 0o644);
let path = FilePath(stringLiteral: fn);
do {
let fd = try FileDescriptor.open(path, mode, options: opts, permissions: permissions)
result(NSNumber(value: fd.rawValue))
} catch {
result(FlutterError(code: "OEPN_FILE_FAILED", message: nil, details: nil))
}
}
class MainFlutterWindow: NSWindow {
override func awakeFromNib() {
@@ -7,9 +55,88 @@ class MainFlutterWindow: NSWindow {
let windowFrame = self.frame
self.contentViewController = flutterViewController
self.setFrame(windowFrame, display: true)
let safChannel = FlutterMethodChannel(
name: "lifegpc.eh_downloader_flutter/saf",
binaryMessenger: flutterViewController.engine.binaryMessenger)
safChannel.setMethodCallHandler { (call, result) in
switch call.method {
case "openFile":
if let args = call.arguments as? Array<Any>,
let fileName = args[0] as? String,
let dir = args[1] as? String,
let mimeType = args[2] as? String,
let readOnly = args[3] as? NSNumber,
let writeOnly = args[4] as? NSNumber,
let append = args[5] as? NSNumber,
let saveAs = args[6] as? NSNumber {
let ext = extFromMimetype(mimeType: mimeType)
if saveAs.boolValue {
let panel = NSSavePanel()
panel.canCreateDirectories = true
panel.canSelectHiddenExtension = true
if let typ = UTType.init(mimeType: mimeType) {
panel.allowedContentTypes = [typ]
}
panel.allowsOtherFileTypes = true
panel.begin { (res) in
if res == NSApplication.ModalResponse.OK {
if let fn = panel.url {
if fn.isFileURL {
let fp = if #available(macOS 13.0, *) {
fn.path(percentEncoded: false)
} else {
fn.path
}
return openFile(result: result, fn: fp, readOnly: readOnly.boolValue, writeOnly: writeOnly.boolValue, append: append.boolValue)
}
}
}
result(FlutterError(code: "USER_CANCELED", message: nil, details: nil))
}
} else {
let fn = NSString.path(withComponents: [dir, fileName]) + (ext ?? "")
openFile(result: result, fn: fn, readOnly: readOnly.boolValue, writeOnly: writeOnly.boolValue, append: append.boolValue)
}
} else {
result(FlutterError(code: "INVALID_ARGUMENTS", message: nil, details: nil))
}
case "writeFile":
if let args = call.arguments as? Array<Any>,
let fd = args[0] as? NSNumber,
let data = args[1] as? FlutterStandardTypedData {
let fD = FileDescriptor(rawValue: fd.int32Value)
do {
let readed = try data.data.withUnsafeBytes{ (re) in
try fD.write(re)
}
result(NSNumber(value: readed))
} catch {
result(FlutterError(code: "WRITE_FILE_FAILED", message: nil, details: nil))
}
} else {
result(FlutterError(code: "INVALID_ARGUMENTS", message: nil, details: nil))
}
case "closeFile":
if let args = call.arguments as? Array<Any>,
let fd = args[0] as? NSNumber {
let fD = FileDescriptor(rawValue: fd.int32Value)
do {
try fD.close()
result(nil)
} catch {
result(FlutterError(code: "CLOSE_FILE_FAILED", message: nil, details: nil))
}
} else {
result(FlutterError(code: "INVALID_ARGUMENTS", message: nil, details: nil))
}
default:
result(FlutterMethodNotImplemented)
}
}
RegisterGeneratedPlugins(registry: flutterViewController)
super.awakeFromNib()
}
}

View File

@@ -6,5 +6,7 @@
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
</dict>
</plist>