You miss the explicit authorization from user to access this file !
It is pretty tricky, and I needed a lot of help from this forum to finally make it work. So, I'll try to speed this up for you. Hope the following is complete.
To do it, you have to call NSOpenPanel and ask there user to select file ; that will authorize access ; if you save the bookmarks, and load them when launching app, that will work next time automatically.
Here is some extract of one of my app to show how to do it :
if let _ = NSMutableData(contentsOf: fileToReadURL) { // based on your fileName ; that is the test I use, may probably use another test
// print("sandbox OK")
} else { // This will occur only first time
let openPanel = NSOpenPanel()
openPanel.message = "Authorize access to file"
openPanel.prompt = "Authorize"
openPanel.canChooseFiles = true
openPanel.canChooseDirectories = false
openPanel.canCreateDirectories = false
openPanel.directoryURL = keyURL
openPanel.begin() {
(result) -> Void in
if (result.rawValue == NSFileHandlingPanelOKButton) {
storeBookmark(openPanel.url!)
saveBookmarks()
}
}
}
if let data = NSMutableData(contentsOf: fileToReadURL) {
// Now you can proceed as with non sandboxed
}
Utility functions needed
I declared a global var :
globalBookmarks = [URL: Data]()
func bookmarkPath() -> String {
// bookmarks saved in document directory
var url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as URL
url = url.appendingPathComponent("Bookmarks.dict")
return url.path
}
func loadBookmarks() {
let path = bookmarkPath()
globalBookmarks = NSKeyedUnarchiver.unarchiveObject(withFile: path) as? [URL: Data] ?? [:] /
for bookmark in globalBookmarks {
restoreBookmark(bookmark)
}
}
func saveBookmarks() {
let path = bookmarkPath()
NSKeyedArchiver.archiveRootObject(globalBookmarks, toFile: path)
}
func storeBookmark(url: URL) {
do {
let data = try url.bookmarkData(options: NSURL.BookmarkCreationOptions.withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil)
globalBookmarks[url] = data
} catch {
Swift.print ("Error storing bookmarks")
}
}
func restoreBookmark(_ bookmark: (key: URL, value: Data)) {
let restoredUrl: URL?
var isStale = false // parameter for URL.init
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 {
// handle if needed
} else {
if !url.startAccessingSecurityScopedResource() {
Swift.print ("Couldn't access: \(url.path)")
} else {
// handle if needed
}
}
}
}
You call loadBookmarks() in applicationDidFinishLaunching