macOS商店沙箱应用程序使用NSOpenPanel选择下载文件文件夹,但无法再次访问该文件夹

我的应用是从网站下载文件。

我为macOS存储启用了项目的沙箱。

macOS商店沙箱应用程序使用NSOpenPanel选择下载文件文件夹,但无法再次访问该文件夹

该应用程序将触发NSOpenPanel,要求用户选择将下载文件(所有文件列表存储在sqlite文件中)保存到的文件夹。 例如:

/home/mymac/myfolder

一切都很好。如果我关闭该应用程序并重新打开它,希望它可以继续下载文件(在sqlite文件中)。

但报告错误:    设置安全信息:禁止操作

系统似乎不允许该应用访问文件夹

/home/mymac/myfolder
再次

如果我使用NSOpenPanel选择系统下载文件夹

/home/mymac/Downloads

关闭应用程序,然后重新打开应用程序,一切正常。 看来系统只允许该应用访问文件夹

/home/mymac/Downloads
再次

欢迎评论

underthesun2008 回答:macOS商店沙箱应用程序使用NSOpenPanel选择下载文件文件夹,但无法再次访问该文件夹

您可以为此使用安全书签。我已经附上了我正在使用的课程:

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所需的窗口实例。您可以在其中一个NSViewController的viewDidAppear中设置实例:

override func viewDidAppear()
{
    super.viewDidAppear()
    SecureFolders.window = NSApplication.shared.mainWindow
}
,

您需要获取URL的书签并永久存储。当您的应用程序打开时,从存储的书签中检索URL。

该方法的描述在文档中:Locating Files Using Bookmarks

您只需要2种方法:

- (NSData*)bookmarkForURL:(NSURL*)url
- (NSURL*)urlForBookmark:(NSData*)bookmark

如果您不希望有很多书签,则可以将书签存储在.plist文件中,甚至可以存储在UserDefaults中。

本文链接:https://www.f2er.com/3138498.html

大家都在问