Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save steipete/40a367b64b57bfd0b44fa8d158fc016c to your computer and use it in GitHub Desktop.
Save steipete/40a367b64b57bfd0b44fa8d158fc016c to your computer and use it in GitHub Desktop.
Using URLByResolvingBookmarkData on Mac Catalyst: Access sandboxed URLs after an app restart.

Here's what needs to be done in order to use security scoped bookmarks on Mac Catalyst:

  1. You need an entitlement: "com.apple.security.files.bookmarks.app-scope" needs to be se to 1.

  2. Pass both NSURLBookmarkCreationWithSecurityScope and NSURLBookmarkCreationSecurityScopeAllowOnlyReadAccess 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 )
  1. 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];
  ```
@hboon
Copy link

hboon commented Jun 28, 2020

Swift:

private let _NSURLBookmarkCreationWithSecurityScope = URL.BookmarkCreationOptions(rawValue: 1 << 11)
private let _NSURLBookmarkCreationSecurityScopeAllowOnlyReadAccess = URL.BookmarkCreationOptions(rawValue: 1 << 12)
private let _NSURLBookmarkResolutionWithSecurityScope = URL.BookmarkResolutionOptions(rawValue: 1 << 10)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment