![](/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.