I have an app that can launch several worker processes, where every worker is a commandline utility. Workers access and create files, so they need security scoped urls. Workers should not provide any UI at all, so bookmark data have to be acquired and stored in the main app and then passed to the workers.
This is how I create bookmark data from security scoped URL acquired from NSOpenPanel
in the main app:
return try url.bookmarkData(options: .withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil)
This data I pass to a worker, and resolve it like this:
//data contains the bookmark data from main app
var isStale = false
secUrl = try URL(resolvingBookmarkData: data, options: [.withSecurityScope], relativeTo: nil, bookmarkDataIsStale: &isStale)
This second code works if launched in the app, but fails in the worker with error message:
The file couldn’t be opened because it isn’t in the correct format.
In the worker I can successfully resolve the url with different options:
secUrl = try URL(resolvingBookmarkData: data, options: [.withoutUI], relativeTo: nil, bookmarkDataIsStale: &isStale)
But then
secUrl.startAccessingSecurityScopedResource()
returns false
.
According to a post in the question here: Using Security Scoped Bookmark in Finder Sync Extension with App Group UserDefaults it is not possible to pass bookmark data with security scope to a subprocess and resolve it there. I find it very strange because you cant expect worker processes to show NSOpenPanels on their own. I believe there has to be a way how to pass access from parent app to subprocess. How to do it?
So it seems that if I do url.startAccessingSecurityScopedResource()
in the main app before the worker process launches, the worker can access resource without any problems. Documentation says that subprocess inherits sandbox from its parent, and this might be the result of it.
So my final solution (which works) is:
startAccessingSecurityScopedResource()
.url.stopAccessingSecurityScopedResource()
on the url from 1)