Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
macOS store sandbox应用程序使用NSOpenPanel选择下载文件文件夹,但无法再次访问该文件夹_Macos_Cocoa_Sandbox - Fatal编程技术网

macOS store sandbox应用程序使用NSOpenPanel选择下载文件文件夹,但无法再次访问该文件夹

macOS store sandbox应用程序使用NSOpenPanel选择下载文件文件夹,但无法再次访问该文件夹,macos,cocoa,sandbox,Macos,Cocoa,Sandbox,我的应用程序是从网站下载文件 我为macOS商店启用了项目的沙箱 应用程序将触发NSOpenPanel,要求用户选择下载文件(所有文件列表存储在sqlite文件中)保存到的文件夹。 例如: /home/mymac/myfolder 一切都好。如果我关闭应用程序并重新打开它,我希望它可以继续下载文件(在sqlite文件中) 但它报告了错误: 设置安全信息:不允许操作 系统似乎不允许应用程序访问该文件夹 /home/mymac/myfolder /home/mymac/Downloads 再

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

我为macOS商店启用了项目的沙箱

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

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

但它报告了错误: 设置安全信息:不允许操作

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

/home/mymac/myfolder
/home/mymac/Downloads
再说一遍

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

/home/mymac/Downloads
关闭应用程序并重新打开应用程序,一切正常。 看起来系统只允许应用程序访问文件夹

/home/mymac/myfolder
/home/mymac/Downloads
再说一遍


欢迎您发表评论

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

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的
视图显示中设置实例:

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

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

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的
视图显示中设置实例:

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

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

操作方法在文档中有描述:

您只需要两种方法:

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

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

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

操作方法在文档中有描述:

您只需要两种方法:

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

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

谢谢,我的问题不是url,而是下载文件夹无法重新打开或访问是的,我明白了。无论您从NSOpenPanel获得什么,都需要将其存储为书签,以便在下次发布时访问。它可能是下载文件夹,不管怎样。另一种方法是将您需要的文件存储在应用程序的目录中。你总是可以访问它。例如:
let downloads=FileManager.default.url(用于:.downloadsDirectory,in:.localDomainMask)。首先
app的目录不能存储用户文件,苹果拒绝了我的应用程序,我使用NSString存储文件夹,我也尝试NSURL NSData存储信息,没有任何更改,重新启动应用程序并访问同一文件夹时出现相同错误“无法在第42249行打开文件os_unix.c:42249:(0)-未定义错误:0”谢谢,我的问题不是url,而是下载文件夹无法重新打开或访问是的,我明白了。无论您从NSOpenPanel获得什么,都需要将其存储为书签,以便在下次发布时访问。它可能是下载文件夹,不管怎样。另一种方法是将您需要的文件存储在应用程序的目录中。你总是可以访问它。例如:
let downloads=FileManager.default.url(用于:.downloadsDirectory,in:.localDomainMask)。首先
app的目录不能存储用户文件,苹果拒绝了我的应用程序,我使用NSString存储文件夹,我也尝试NSURL NSData存储信息,没有任何更改,重新启动应用程序并访问同一文件夹时出现相同错误“无法在第42249行打开文件os_unix.c:42249:(0)-未定义错误:0”谢谢,我的问题不是url,而是下载文件夹无法重新打开或访问Hanks,我的问题不是url,而是下载文件夹无法重新打开或访问