Mac OS应用程序中用户所选文件夹的读写权限?

时间:2017-12-20 09:43:32

标签: swift macos cocoa

我正在开发MAC OS应用程序,它具有代表您创建文件的功能。第一个用户选择用于存储文件的文件夹(在应用程序启动时一次),然后用户可以使用苹果脚本选择要在所选文件夹上创建的文件的类型和名称(在应用程序启动时选择的文件夹)。当我在权利文件中添加temporary-exception以下时,我可以创建文件,但是它无法应用苹果审核小组,但可以在沙盒中使用。

  

准则2.4.5(i) - 表现   我们已确定为此应用程序请求的一个或多个临时权利例外不合适且不会被授予:

com.apple.security.temporary-exception.files.home-relative-path.read-write
/FolderName/

我找到了:

Enabling App Sandbox - 允许应用编写可执行文件。

并且

Enabling User-Selected File Access - Xcode在目标编辑器的“摘要”选项卡中提供了一个弹出菜单,其中包含对用户明确选择的文件和文件夹进行只读或读/写访问的选项。当您启用用户选择的文件访问权限时,您可以以编程方式访问用户使用NSOpenPanel对象打开的文件和文件夹,以及用户使用NSSavePanel对象保存的文件。

使用以下代码创建文件:

let str = "Super long string here"
let filename = getDocumentsDirectory().appendingPathComponent("/xyz/output.txt")

do {
    try str.write(to: filename, atomically: true, encoding: String.Encoding.utf8)
} catch {
    // failed to write file – bad permissions, bad filename, missing permissions, or more likely it can't be converted to the encoding
}

还尝试在NSOpenPanel对象的权利文件中添加com.apple.security.files.user-selected.read-write

<key>com.apple.security.files.user-selected.read-write</key>
<true/>

有没有办法让Apple审核小组批准对用户所选文件夹具有读写权限的Mac App?

4 个答案:

答案 0 :(得分:5)

这是我的答案 如何在Mac OS应用程序中实现和持久保存用户所选文件夹的读写权限?

GitHub Example Project link

第一:

在权利文件中添加user-selectedbookmarks.app权限:

<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.files.bookmarks.app-scope</key>
<true/>

然后我为存储,加载...等书签应用程序所需的所有书签相关功能创建了类。

import Foundation
import Cocoa

var bookmarks = [URL: Data]()

func openFolderSelection() -> URL?
{
    let openPanel = NSOpenPanel()
    openPanel.allowsMultipleSelection = false
    openPanel.canChooseDirectories = true
    openPanel.canCreateDirectories = true
    openPanel.canChooseFiles = false
    openPanel.begin
        { (result) -> Void in
            if result.rawValue == NSApplication.ModalResponse.OK.rawValue
            {
                let url = openPanel.url
                storeFolderInBookmark(url: url!)
            }
    }
    return openPanel.url
}

func saveBookmarksData()
{
    let path = getBookmarkPath()
    NSKeyedArchiver.archiveRootObject(bookmarks, toFile: path)
}

func storeFolderInBookmark(url: URL)
{
    do
    {
        let data = try url.bookmarkData(options: NSURL.BookmarkCreationOptions.withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil)
        bookmarks[url] = data
    }
    catch
    {
        Swift.print ("Error storing bookmarks")
    }

}

func getBookmarkPath() -> String
{
    var url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as URL
    url = url.appendingPathComponent("Bookmarks.dict")
    return url.path
}

func loadBookmarks()
{
    let path = getBookmarkPath()
    bookmarks = NSKeyedUnarchiver.unarchiveObject(withFile: path) as! [URL: Data]
    for bookmark in bookmarks
    {
        restoreBookmark(bookmark)
    }
}



func restoreBookmark(_ bookmark: (key: URL, value: Data))
{
    let restoredUrl: URL?
    var isStale = false

    Swift.print ("Restoring \(bookmark.key)")
    do
    {
        restoredUrl = try URL.init(resolvingBookmarkData: bookmark.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)")
            }
        }
    }

}

然后使用NSOpenPanel打开文件夹选择,以便用户可以选择允许您访问的文件夹。 NSOpenPanel必须存储为书签并保存到磁盘。然后,您的应用将具有与用户选择文件夹时相同的访问级别。

打开NSOpenPanel

let selectedURL = openFolderSelection()
saveBookmarksData()

并在应用关闭后加载现有书签:

loadBookmarks()

多数民众赞成。 我希望它会帮助别人。

答案 1 :(得分:3)

在权利文件中添加user-selectedbookmarks.app权限:

<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.files.bookmarks.app-scope</key>
<true/>

然后使用NSOpenPanel打开文件夹选择,以便用户可以选择允许您访问的文件夹。 NSOpenPanel必须存储为书签并保存到磁盘。然后,您的应用将具有与用户选择文件夹时相同的访问级别。

答案 2 :(得分:0)

更新到 Swift 5(感谢 Jay!)

structure(list(surname_sender = c("Ajite", "Dikmen", "Dikmen", 
"Dikmen", "Dikmen", "Jylmaz", "Jylmaz", "Jylmaz", "Kandejas", 
"Kandejas", "Kandejas", "Kandejas", "Kizildag", "Kizildag", "Kizildag", 
"Kizildag", "Kizildag", "Motta", "Motta", "Motta", "Motta", "Motta", 
"Motta", "Nordfel'dt", "Nordfel'dt", "Poloma", "Sio", "Ture", 
"Ture", "Ture", "Ture", "Ture", "Uhansson", "Uhansson", "Uhansson", 
"Uhansson"), surname_receiver = c("Poloma", "Kizildag", "Poloma", 
"Ture", "Uhansson", "Kandejas", "Poloma", "Uhansson", "Motta", 
"Nordfel'dt", "Ture", "Uhansson", "Dikmen", "Motta", "Nordfel'dt", 
"Ture", "Uhansson", "Dikmen", "Jylmaz", "Kizildag", "Poloma", 
"Ture", "Uhansson", "Ture", "Uhansson", "Ture", "Dikmen", "Jylmaz", 
"Kandejas", "Kizildag", "Motta", "Poloma", "Kandejas", "Kizildag", 
"Sio", "Uhansson"), passes = c(4L, 4L, 4L, 4L, 6L, 4L, 5L, 4L, 
4L, 5L, 4L, 9L, 10L, 6L, 4L, 5L, 8L, 5L, 4L, 6L, 4L, 4L, 5L, 
4L, 6L, 13L, 5L, 5L, 4L, 9L, 8L, 7L, 14L, 8L, 5L, 4L), mean_passer_x = c(64.7, 
44.41875, 44.41875, 44.41875, 44.41875, 68.725, 68.725, 68.725, 
75.2919444444445, 75.2919444444445, 75.2919444444445, 75.2919444444445, 
29.5423333333333, 29.5423333333333, 29.5423333333333, 29.5423333333333, 
29.5423333333333, 44.31, 44.31, 44.31, 44.31, 44.31, 44.31, 8.60416666666667, 
8.60416666666667, 58.6384615384615, 52.46, 38.2090952380952, 
38.2090952380952, 38.2090952380952, 38.2090952380952, 38.2090952380952, 
51.7642857142857, 51.7642857142857, 51.7642857142857, 51.7642857142857
), mean_passer_y = c(46.9, 38.7083333333333, 38.7083333333333, 
38.7083333333333, 38.7083333333333, 35.3533333333333, 35.3533333333333, 
35.3533333333333, 10.7833333333333, 10.7833333333333, 10.7833333333333, 
10.7833333333333, 23.6785, 23.6785, 23.6785, 23.6785, 23.6785, 
34.6552777777778, 34.6552777777778, 34.6552777777778, 34.6552777777778, 
34.6552777777778, 34.6552777777778, 32.2166666666667, 32.2166666666667, 
65.3, 25.7, 46.9388571428571, 46.9388571428571, 46.9388571428571, 
46.9388571428571, 46.9388571428571, 7.25, 7.25, 7.25, 7.25)), row.names = c(NA, 
-36L), class = c("tbl_df", "tbl", "data.frame"))

答案 3 :(得分:-1)

我在这里找到了最佳且可行的答案-reusing security scoped bookmark

超级简单,易于理解,并且做得很好。

解决方案是:-

var userDefault = NSUserDefaults.standardUserDefaults()
var folderPath: NSURL? {
    didSet {
        do {
            let bookmark = try folderPath?.bookmarkDataWithOptions(.SecurityScopeAllowOnlyReadAccess, includingResourceValuesForKeys: nil, relativeToURL: nil)
            userDefault.setObject(bookmark, forKey: "bookmark")
        } catch let error as NSError {
            print("Set Bookmark Fails: \(error.description)")
        }
    }
}

func applicationDidFinishLaunching(aNotification: NSNotification) {
    if let bookmarkData = userDefault.objectForKey("bookmark") as? NSData {
        do {
            let url = try NSURL.init(byResolvingBookmarkData: bookmarkData, options: .WithoutUI, relativeToURL: nil, bookmarkDataIsStale: nil)
            url.startAccessingSecurityScopedResource()
        } catch let error as NSError {
            print("Bookmark Access Fails: \(error.description)")
        }
    }
}