簡體   English   中英

macOS 商店沙盒應用使用 NSOpenPanel 到 select 下載文件夾,但無法再次訪問該文件夾

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM