I’m creating a macOS app which ships with some .zip files within its Bundle directory.
Users should be able to save these files from my app to a custom directory.
I found NSSavePanel
and thought it is the right approach — that’s what I have so far:
@IBAction func buttonSaveFiles(_ sender: Any) {
let savePanel = NSSavePanel()
let bundleFile = Bundle.main.resourcePath!.appending("/MyCustom.zip")
let targetPath = NSHomeDirectory()
savePanel.directoryURL = URL(fileURLWithPath: targetPath.appending("/Desktop"))
// Is appeding 'Desktop' a good solution in terms of localisation?
savePanel.message = "My custom message."
savePanel.nameFieldStringValue = "MyFile"
savePanel.showsHiddenFiles = false
savePanel.showsTagField = false
savePanel.canCreateDirectories = true
savePanel.allowsOtherFileTypes = false
savePanel.isExtensionHidden = true
savePanel.beginSheetModal(for: self.view.window!, completionHandler: {_ in })
}
I couldn’t find out how to 'hand over' the bundleFile
to the savePanel
.
So my main question is: How can I save/copy a file from the app bundle to a custom directory?
Additional questions depending NSSavePanel
: 1) It seems that it’s not localized by default (my Xcode scheme is set to German, but the panel appears in English), do I have to customize that by myself? 2) Is there a way to present the panel expanded by default?
You should use Bundle.main.url
to get your existing file URL, then get the destination URL with the panel, then copy the file. The panel doesn't do anything to files, it just gets their URL.
Example:
// the panel is automatically displayed in the user's language if your project is localized
let savePanel = NSSavePanel()
let bundleFile = Bundle.main.url(forResource: "MyCustom", withExtension: "zip")!
// this is a preferred method to get the desktop URL
savePanel.directoryURL = FileManager.default.urls(for: .desktopDirectory, in: .userDomainMask).first!
savePanel.message = "My custom message."
savePanel.nameFieldStringValue = "MyFile"
savePanel.showsHiddenFiles = false
savePanel.showsTagField = false
savePanel.canCreateDirectories = true
savePanel.allowsOtherFileTypes = false
savePanel.isExtensionHidden = true
if let url = savePanel.url, savePanel.runModal() == NSFileHandlingPanelOKButton {
print("Now copying", bundleFile.path, "to", url.path)
// Do the actual copy:
do {
try FileManager().copyItem(at: bundleFile, to: url)
} catch {
print(error.localizedDescription)
}
} else {
print("canceled")
}
Also, note that the panel being expanded or not is a user selection, you can't force it from your app.