For example when a user opens a file or folder from within a NSOpenPanel the application automatically receives access rights to that file/folder.
But when the path is saved to disk, and the application wants to use this path in the next session, the sandbox will interfere and deny access rights.
Luckily Apple has also created a solution for this: the path can be stored as a "Security Scoped Bookmark". The application can -in later sessions- read this data, create a new URL from it and then request the OS (sandbox) to reinstate the same rights as in the previous session. A bit of work, but not intrinsically difficult.
Here is how to create a Security Scoped Bookmark:
// Retrieve the bookmark data from the URL and add it to the bookmarks
var error: NSError?
if let data: NSData? = url.bookmarkDataWithOptions(
NSURLBookmarkCreationOptions.WithSecurityScope,
includingResourceValuesForKeys: nil,
relativeToURL: nil,
error: &error) {
bookmarks[path] = data
} else { // 'data' is nil, there should be an error message
let detail = error?.localizedDescription ?? "missing error description"
}
The NSData must be saved to file when the session ends:
// Create a string that contains the security scoped bookmark data
let bytes = data.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.allZeros)
... save the bytes to file using your favourite method
// Recreate the security scoped bookmark url
var isStale: ObjCBool = false
var error: NSError?
let url = NSURL(
byResolvingBookmarkData: data,
options: NSURLBookmarkResolutionOptions.WithSecurityScope,
relativeToURL: nil,
bookmarkDataIsStale: &isStale,
error: &error)
if error != nil {
... error handling
} else if isStale { // Exclude stale resources
... error handling
} else if url == nil { // Should never happen when error == nil !!
... error handling
} else {
// Regain the access rights
if !url!.startAccessingSecurityScopedResource() {
errorMessage += "Could not gain access rights for: \(url!.path!)\r\n"
}
}
}
url.stopAccessingSecurityScopedResource()
Failure to release security scoped bookmarks will result in memory leaks within the kernel. This may or may not be a problem for your application, depending on how many resources it needs.
If you want to speed up your development process even more, get our fully functional SecurityScopedBookmarks example. Depending on your experience, this could easily save you a days work for the price of a (cheap) cup of coffee ($2). And you will be helping to keep this blog alive.
Happy coding...
Did this help?, then please help out a small independent.
If you decide that you want to make a small donation, you can do so by clicking this
link: a cup of coffee ($2) or use the popup on the right hand side for different amounts.
Payments will be processed by PayPal, receiver will be sales at balancingrock dot nl
Bitcoins will be gladly accepted at: 1GacSREBxPy1yskLMc9de2nofNv2SNdwqH
We don't get the world we wish for... we get the world we pay for.
Thanks for the concise description. Note that with newer Swift versions you need to enclose it in a do/try/catch since both bookmark methods are Throws.
ReplyDeleteThanks Thomas,
ReplyDeleteAfter Swift 3 ships I am planning to do a complete overhaul of all my posts.