mirror of
https://github.com/lifegpc/eh_downloader_flutter.git
synced 2026-06-06 05:49:03 +08:00
Add basic file writing for macos
This commit is contained in:
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user