![](/img/trans.png)
[英]NSOpenPanel under Sandbox - Access All Files inside User Selected folder
[英]macOS store sandbox app uses NSOpenPanel to select download file folder, but can not access the folder again
我的应用程序是从 web 站点下载文件。
我为 macOS 商店启用了项目的沙箱。
该应用程序将触发 NSOpenPanel 询问用户 select 下载文件(所有文件列表存储在 sqlite 文件中)的文件夹。 例如:
/home/mymac/myfolder
一切都好。 如果我关闭应用程序并重新打开它,我希望它可以继续下载文件(在 sqlite 文件中)。
但是报错:设置安全信息:不允许操作
看起来系统不允许应用程序访问该文件夹
/home/mymac/myfolder
再次。
如果我使用 NSOpenPanel 到 select 系统下载文件夹
/home/mymac/Downloads
关闭应用程序并重新打开应用程序,一切正常。 看起来系统只允许应用访问文件夹
/home/mymac/Downloads
再次。
欢迎您的评论
您可以为此使用安全书签。 我附上了我正在使用的 class:
import Foundation
import Cocoa
public class SecureFolders
{
public static var window: NSWindow?
private static var folders = [URL : Data]()
private static var path: String?
public static func initialize(_ path: String)
{
self.path = path
}
public static func load()
{
guard let path = self.path else { return }
if !FileManager.default.fileExists(atPath: path)
{
return
}
if let rawData = NSData(contentsOfFile: path)
{
let data = Data(referencing: rawData)
if let folders = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? [URL : Data]
{
for folder in folders
{
self.restore(folder)
}
}
}
}
public static func remove(_ url: URL)
{
folders.removeValue(forKey: url)
}
public static func store(url: URL)
{
guard let path = self.path else { return }
do
{
let data = try NSKeyedArchiver.archivedData(withRootObject: self.folders, requiringSecureCoding: false)
self.folders[url] = data
if let url = URL(string: path)
{
try? data.write(to: url)
}
}
catch
{
Swift.print("Error storing bookmarks")
}
}
public static func restore(_ folder: (key: URL, value: Data))
{
let restoredUrl: URL?
var isStale = false
do
{
restoredUrl = try URL.init(resolvingBookmarkData: folder.value, options: NSURL.BookmarkResolutionOptions.withSecurityScope, relativeTo: nil, bookmarkDataIsStale: &isStale)
}
catch
{
Swift.print("Error restoring bookmarks")
restoredUrl = nil
}
if let url = restoredUrl
{
if isStale
{
Swift.print ("URL is stale")
}
else
{
if !url.startAccessingSecurityScopedResource()
{
Swift.print ("Couldn't access: \(url.path)")
}
self.folders[url] = folder.value
}
}
}
public static func allow(folder: String, prompt: String, callback: @escaping (URL?) -> ())
{
let openPanel = NSOpenPanel()
openPanel.directoryURL = URL(string: folder)
openPanel.allowsMultipleSelection = false
openPanel.canChooseDirectories = true
openPanel.canCreateDirectories = false
openPanel.canChooseFiles = false
openPanel.prompt = prompt
openPanel.beginSheetModal(for: self.window!)
{
result in
if result == NSApplication.ModalResponse.OK
{
let url = openPanel.url
self.store(url: url!)
callback(url)
}
else
{
callback(nil)
}
}
}
public static func isStored(_ directory: Directory) -> Bool
{
return isStored(path: IO.getDirectory(directory))
}
public static func remove(_ directory: Directory)
{
let path = IO.getDirectory(directory)
self.remove(path)
}
public static func remove(_ path: String)
{
let url = URL(fileURLWithPath: path)
self.remove(url)
}
public static func isStored(path: String) -> Bool
{
let absolutePath = URL(fileURLWithPath: path).path
for url in self.folders
{
if url.key.path == absolutePath
{
return true
}
}
return false
}
public static func areStored(_ directories: [Directory]) -> Bool
{
for dir in directories
{
if isStored(dir) == false
{
return false
}
}
return true
}
public static func areStored(_ paths: [String]) -> Bool
{
for path in paths
{
if isStored(path: path) == false
{
return false
}
}
return true
}
}
用法:
fileprivate func initialize() // Put a call to this in func applicationDidFinishLaunching(_ aNotification: Notification)
{
let directories = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let path = directories[0].appending("/SecureBookmarks.dict")
SecureFolders.initialize(path)
SecureFolders.load()
}
要将文件夹添加到安全书签:
fileprivate func allow(_ path: String)
{
SecureFolders.allow(folder: path, prompt: "Open")
{
result in
// Update controls or whatever
}
}
不要忘记设置显示 NSOpenPanel 所需的NSOpenPanel
实例。 您可以在您的 NSViewController 之一的viewDidAppear
中设置实例:
override func viewDidAppear()
{
super.viewDidAppear()
SecureFolders.window = NSApplication.shared.mainWindow
}
您需要获取 URL 的书签并将其永久存储。 当您的应用程序打开时,从存储的书签中检索 URL。
文档中描述了这样做的方法: Locating Files Using Bookmarks
您只需要两种方法:
- (NSData*)bookmarkForURL:(NSURL*)url
- (NSURL*)urlForBookmark:(NSData*)bookmark
如果您不希望有很多书签,您可以将书签存储在.plist
文件中,甚至可以存储在 UserDefaults 中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.