Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

startAccessingSecurityScopedResource() returns false even when access to a file is allowed

I have an iOS app which has an action extension to save documents in it.

The method startAccessingSecurityScopedResource() returns false in some cases even when I am able to access the file.

BOOL success = [originalURL startAccessingSecurityScopedResource];    
if (success) {
    NSFileCoordinator *fileCoordinator = [[NSFileCoordinator alloc] init];
    NSError *error = nil;
    [fileCoordinator coordinateReadingItemAtURL:originalURL options:NSFileCoordinatorReadingForUploading error:&error byAccessor:^(NSURL *newURL) { 
        //My Code
    }
}

In the above code, the following is observed

When sharing a file from Apple's Photos App

originalURL = file:///var/mobile/Media/PhotoData/OutgoingTemp/49152B46-E719-41A5-A5D5-21EAE6254246/RenderedPhoto/IMG_0026.JPG 

When sharing a file from MS Word App

originalURL = file:///private/var/mobile/Containers/Data/Application/1B0C962F-E7B4-46ED-A9DA-A8213E05A470/tmp/ShareAttachments/%7BC699DC26-37F9-A949-8F69-1F9D6981C4B0%7D/Document.docx

When sharing a file from Apple's Pages App

originalURL = file:///private/var/mobile/Containers/Data/Application/CDBBDC79-02C7-4ABF-A6B9-F38B6540E2B1/Documents/Document%20(1).pages

The flag success is true in the first case (Photos App), but is false in the other two (Word & Pages App).

If I remove the success flag check, I am able to access all the three files using the NSFileCoordinator and am able to copy the file into my app.

Therefore, I am not sure why is the method startAccessingSecurityScopedResource() returning false for a scenario where I clearly have the access to copy the file.

The motive is to save the file exported from the file editor app into my iOS app using the action extension.

like image 601
Sandeep T D S Avatar asked Feb 02 '18 09:02

Sandeep T D S


2 Answers

I only use success to determine either I need to call stopAccessingSecurityScopedResource() or not inside NSFileCoordinator completion handler.

BOOL success = [originalURL startAccessingSecurityScopedResource];
NSFileCoordinator *fileCoordinator = [[NSFileCoordinator alloc] init];
NSError *error = nil;
[fileCoordinator coordinateReadingItemAtURL:originalURL options:NSFileCoordinatorReadingForUploading error:&error byAccessor:^(NSURL *newURL) { 
    //My Code
    if (success) {
        [originalURL stopAccessingSecurityScopedResource];
    }
}

Please note according to Apple's documentation,in case you don't call stopAccessingSecurityScopedResource():

If you fail to relinquish your access to file-system resources when you no longer need them, your app leaks kernel resources. If sufficient kernel resources are leaked, your app loses its ability to add file-system locations to its sandbox, such as via Powerbox or security-scoped bookmarks, until relaunched.

like image 52
Mousavian Avatar answered Nov 04 '22 08:11

Mousavian


If the file you are trying to access is an external document, which is outside your app's sandbox, then you will need startAccessingSecurityScopedResource() to access the file and it will return true.

If you are accessing documents which are your app's assets or you don't have authorisation, the method will return false.

Refer to this Apple Doc of UIDocumentPickerViewController. It uses NSFileCoordinator to read and write to external documents.

like image 38
Lawliet Avatar answered Nov 04 '22 07:11

Lawliet