Mac OS应用程序中用户选择的文件夹的读写权限?
Posted
技术标签:
【中文标题】Mac OS应用程序中用户选择的文件夹的读写权限?【英文标题】:Read and write permission for user selected folder in Mac OS app? 【发布时间】:2017-12-20 09:43:32 【问题描述】:我正在开发 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/>
有什么方法可以通过苹果审核团队来批准对用户选择的文件夹具有读写权限的 Mac App?
【问题讨论】:
如果用户总是选择目标文件夹(意思是,如果你的应用在没有用户操作的情况下不尝试写入)那么你只需要 com.apple.security.files.user-selected.read - 写,没有别的。 使用安全范围的书签。 @Moritz 是的,但我想要一次文件夹选择,然后每个文件都将存储在同一个位置。 那么你仍然只需要 com.apple.security.files.user-selected.read-write 但你必须使用安全范围的书签,正如 El Tomato 刚才所说的那样。 使用安全范围的书签。应用程序可以要求文件夹访问权限一次,然后单击按钮,他可以在同一位置创建和保存文档。 @El Tomato 请提供一些参考网站(developer.apple.com 除外) 【参考方案1】:这是我的答案 如何在 Mac OS 应用中实现和持久化用户选择文件夹的读写权限?
GitHub Example Project link
第一:
在授权文件中添加user-selected
和bookmarks.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()
就是这样。 我希望它会对某人有所帮助。
【讨论】:
除了user-selected
、movies
、pictures
等之外,我们可以定义自定义文件夹read/write
访问吗?OK likeDocuments
Sid 看起来很有趣,但我无法编译您的 GitHub 项目,因为它在 func loadBookmarks() 中崩溃。
安迪,你是对的。我编辑了代码以解决该问题。基本上,如果从未保存过书签,那么您将无法加载它们并强制展开。【参考方案2】:
在授权文件中添加user-selected
和bookmarks.app
权限:
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.files.bookmarks.app-scope</key>
<true/>
然后使用NSOpenPanel
打开文件夹选择,以便用户可以选择允许您访问的文件夹。 NSOpenPanel
必须存储为书签并保存到磁盘。然后,您的应用将拥有与用户选择文件夹时相同的访问级别。
【讨论】:
感谢您的回复,我会试试这个。【参考方案3】:我在这里找到了最佳且有效的答案 - 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)")
【讨论】:
【参考方案4】:已更新至 Swift 5(感谢 Jay!)
var folderPath: URL?
didSet
do
let bookmark = try folderPath?.bookmarkData(options: .securityScopeAllowOnlyReadAccess, includingResourceValuesForKeys: nil, relativeTo: nil)
UserDefaults.standard.set(bookmark, forKey: "bookmark")
catch let error as NSError
print("Set Bookmark Fails: \(error.description)")
func applicationDidFinishLaunching(_ aNotification: Notification)
if let bookmarkData = UserDefaults.standard.object(forKey: "bookmark") as? Data
do
var bookmarkIsStale = false
let url = try URL.init(resolvingBookmarkData: bookmarkData as Data, options: .withSecurityScope, relativeTo: nil, bookmarkDataIsStale: &bookmarkIsStale)
url.startAccessingSecurityScopedResource()
catch let error as NSError
print("Bookmark Access Fails: \(error.description)")
【讨论】:
以上是关于Mac OS应用程序中用户选择的文件夹的读写权限?的主要内容,如果未能解决你的问题,请参考以下文章