How to use iOS security scoped bookmarks across devices?

543 views Asked by At

On iOS (14/15) I'm trying to pass security scoped bookmarks to user picked files on iCloud Drive between devices but whatever I try: I cannot get urls to be restored on another device running the same app.

The app is a UIDocument based app, the code below is in a UIViewController that display the document. The document is created like so:

Document* document = [[Document alloc] initWithFileURL:documentURL];

and then passed on to the ViewController

The url that's going to be bookmarked is picked using a plain UIDocumentPickerViewController

This is how I create a security scoped bookmark:

// Toggle this to create either a document scoped url or an app scoped url
static BOOL DOC_SCOPE = NO;

- (void) documentPicker:(UIDocumentPickerViewController*)controller didPickDocumentsAtURLs:(NSArray <NSURL *>*)urls {
    if (urls.count > 0) {
        NSURL* url = urls.firstObject;
        NSURL* docURL = self.document.fileURL;
        BOOL closeSource = [docURL startAccessingSecurityScopedResource];
        BOOL doClose = [url startAccessingSecurityScopedResource];
        NSData* bookmark = [url bookmarkDataWithOptions:0 includingResourceValuesForKeys:nil relativeToURL:DOC_SCOPE?docURL:nil error:nil];
        if (doClose)
            [url stopAccessingSecurityScopedResource];
        if (closeSource)
            [docURL stopAccessingSecurityScopedResource];
        NSString* encoded =  [NSString stringWithFormat:@"\n[%@]\n", [bookmark base64EncodedStringWithOptions:0]];

At this point I insert the encoded bookmark data in the document data and save the document.

When opening the linked document the bookmark and url are restored like so:

openLink:(NSString*)encoded {
    NSData* bookmark = [[NSData alloc] initWithBase64EncodedString:encoded options:0];
    NSURL* docURL = self.document.fileURL;
    BOOL closeSource = [docURL startAccessingSecurityScopedResource];
    NSError* error = nil;
    NSURL* url = [NSURL URLByResolvingBookmarkData:bookmark options:0 relativeToURL:DOC_SCOPE?docURL:nil bookmarkDataIsStale:nil error:&error];
    if (error != nil)
        NSLog(@"%@", error.localizedFailureReason);
    if (url != nil) {
        BOOL doClose = [url startAccessingSecurityScopedResource];
        // here use the url to access linked file
        if (doClose)
            [url stopAccessingSecurityScopedResource];
    }
    if (closeSource)
        [docURL stopAccessingSecurityScopedResource];
}

To the project's entitlements I have added

com.apple.security.files.bookmarks.app-scope = 1
com.apple.security.files.bookmarks.document-scope = 1

When on the same device I can the restore the bookmark data and get access to the restored URL OK, but when opening the same file on another device, [NSURL URLByResolvingBookmarkData...] always sets an error:

Error Domain=NSCocoaErrorDomain Code=257 "The file couldn’t be opened because you don’t have permission to view it."

This is both the case for app scope book marks and document scope book marks.

Any idea what's missing / how to get this working?

0

There are 0 answers