Here's what needs to be done in order to use security scoped bookmarks on Mac Catalyst:
-
You need an entitlement: "com.apple.security.files.bookmarks.app-scope" needs to be se to 1.
-
Pass both
NSURLBookmarkCreationWithSecurityScope
andNSURLBookmarkCreationSecurityScopeAllowOnlyReadAccess
when creating the bookmark.
Note: The headers mark these API as unavailable for iOS, and this indeed does only work on Mac and not iOS. However, Mac Catalyst really is a Mac app, so using these values is fine. In order to allow compilation, use following:
#define NSURLBookmarkCreationWithSecurityScope ( 1 << 11 )
#define NSURLBookmarkCreationSecurityScopeAllowOnlyReadAccess ( 1 << 12 )
- You need to pass
NSURLBookmarkResolutionWithSecurityScope
when resolving the bookmark. Again, use following define in order to allow compilation:
#define NSURLBookmarkResolutionWithSecurityScope ( 1 << 10 )
Note: hen you get a URL back from UIDocumentBrowserViewController
, the app should already have a sandbox extension and not require -startAccessing
.
Sample code follows:
// Saving a bookmark:
NSError *error;
// UIDocumentBrowserViewController provides only read-only access to URLs
NSURLBookmarkCreationOptions options = NSURLBookmarkCreationWithSecurityScope | NSURLBookmarkCreationSecurityScopeAllowOnlyReadAccess;
NSData *data = [sourceURL bookmarkDataWithOptions:options
includingResourceValuesForKeys:nil
relativeToURL:nil
error:&error];
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"catalyst.bookmark"];
[data writeToFile:path atomically:NO];
// Loading a bookmark:
NSError *error;
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"catalyst.bookmark"];
NSData *bookmark = [NSData dataWithContentsOfFile:path];
NSURL *url = [NSURL URLByResolvingBookmarkData:bookmark
options:NSURLBookmarkResolutionWithSecurityScope
relativeToURL:nil bookmarkDataIsStale:nil error:&error];
if (!url) {
NSLog(@"Error: %@", error);
return YES;
}
NSLog(@"URL = %@", url);
if ( ![url startAccessingSecurityScopedResource] ) {
NSLog(@"Failed to startAccessingSecurityScopedResource");
return YES;
}
NSData *data = [NSData dataWithContentsOfURL:url];
if (!data) {
NSLog(@"Failed to read data");
}
NSLog(@"Data: %@", data);
[url stopAccessingSecurityScopedResource];
```
Documentation: https://developer.apple.com/library/archive/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html#//apple_ref/doc/uid/TP40011195-CH4-SW18