I am developing MAC OS app which have functionality to create file on the behalf of your. First user select folder for storing file (One time at start of app) and then user
Here is my Answer How to do implement and persist Read and write permission of user selected folder in Mac OS app?
GitHub Example Project link
First :
Add user-selected
and bookmarks.app
permissions in entitlement file :
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.files.bookmarks.app-scope</key>
<true/>
Then i created class for all bookmark related function required for storeing, loading ... etc bookmarks app.
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)")
}
}
}
}
Then open folder selection using NSOpenPanel
so the user can select which folders to give you access to. The NSOpenPanel
must be stored as a bookmark and saved to disk. Then your app will have the same level of access as it did when the user selected the folder.
To open NSOpenPanel
:
let selectedURL = openFolderSelection()
saveBookmarksData()
and to load existing bookmark after app close :
loadBookmarks()
Thats it. I Hope it will help someone.
I found the best and working answer here - reusing security scoped bookmark
Super simple, easy to understand and does the job pretty well.
The solution was :-
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)")
}
}
}
Add user-selected
and bookmarks.app
permissions in entitlement file :
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.files.bookmarks.app-scope</key>
<true/>
Then open folder selection using NSOpenPanel
so the user can select which folders to give you access to. The NSOpenPanel
must be stored as a bookmark and saved to disk. Then your app will have the same level of access as it did when the user selected the folder.