I'm experiencing problems (on Mojave and Catalina) with "reusing" security scope URL bookmark for a folder between app launches in my app.
It's simple decompressing application using libarchive framework. User selects file to decompress, I want to store URL bookmark for it's parent folder (e.g. ~/Desktop), and reuse it next time user tries to decompress file in the same folder.
First, I added following to my app's entitlements file:
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.bookmarks.app-scope</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
When accessing file (parent folder respectively) for the first time:
1. User selects file to decompress
2. I present NSOpenPanel to obtain access to the file folder:
let directoryURL = fileURL.deletingLastPathComponent()
let openPanel = NSOpenPanel()
openPanel.allowsMultipleSelection = false
openPanel.canChooseDirectories = true
openPanel.canCreateDirectories = false
openPanel.canChooseFiles = false
openPanel.prompt = "Grant Access"
openPanel.directoryURL = directoryURL
openPanel.begin { [weak self] result in
guard let self = self else { return }
// WARNING: It's absolutely necessary to access NSOpenPanel.url property to get access
guard result == .OK, let url = openPanel.url else {
// HANDLE ERROR HERE ...
return
}
// We got URL and need to store bookmark's data
// ...
}
3. I obtain bookmark data of folder URL and store it to keyed archive:
let data = try url.bookmarkData(options: .withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil)
bookmarks[url] = data
NSKeyedArchiver.archiveRootObject(bookmarks, toFile: bookmarksPath)
4. Now I start using file URL and use libarchive to decompress .zip file to it's parent folder:
fileURL.startAccessingSecurityScopedResource()
// Decompressing file with libarchive...
fileURL.stopAccessingSecurityScopedResource()
5. Everything is working as expected, .zip file gets decompressed
When relaunching app, decompressing file in the same folder, reusing saved bookmark data:
1. I get bookmarks from keyed archive:
let bookmarks = NSKeyedUnarchiver.unarchiveObject(withFile: bookmarksPath) as? [URL: Data]
2. I get bookmark data from bookmarks for the file's parent folder and resolve it:
let directoryURL = fileURL.deletingLastPathComponent()
let data = bookmarks[directoryURL]!
var isStale = false
let newURL = try URL(resolvingBookmarkData: data, options: .withSecurityScope, relativeTo: nil, bookmarkDataIsStale: &isStale)
3. Now again I start using file URL and use libarchive to decompress .zip file to it's parent folder:
fileURL.startAccessingSecurityScopedResource()
// Decompressing file with libarchive...
fileURL.stopAccessingSecurityScopedResource()
But this time libarchive returns error saying
Failed to open \'/Users/martin/Desktop/Archive.zip\'
I know I might be doing something terribly wrong or not understanding concept of security scoped URL bookmarks but can't find where's the problem. Any hints?
I also tried to start accessing folderURL instead of fileURL but it keeps returning false and not working either:
let success = folderURL.startAccessingSecurityScopedResource()