Search code examples
macoscocoasandboxdocument-based

OS X App Sandboxing and arbitrary files access - Update to Document-based?


My OS X app (currently not sandboxed) accesses files contained inside a directory set by the user (one chooses the path with a NSOpenPanel and a reference to this path is kept throughout execution). The list of files is generated via NSDirectoryEnumerator and I then read from and write to those files using AVAsset and taglib (in C++ with a bridging header) respectively.

As expected, enabling Sandboxing in Xcode rendered the app useless, the list of files given by NSDirectoryEnumerator is empty and even if it weren't, I would not be able to read from and write to the files. What are the steps I need to take to make my app sandbox-compliant?

Does my app need to be document based? Can my app really be "document-based" since I don't really have proper documents (as in: I don't have a window per file, it doesn't seem to comply to the standard document-based app model)? My app is basically just a table view with files references as rows. Another important point: can I still use taglib to write to my files if my app is document-based ? I need to pass taglib the path to my file as a string pointer in order for it to work.

Thanks a lot, this topic is quite confusing at the moment.


Solution

  • You don't have to convert your app to be document-based to gain access to user selected files and security scoped bookmarks.

    I can think of 2 reasons why your current code does not work in a sandboxed environment:

    • You don't have the "User Selected File Access" capability set (Xcode > target > Capabilities > App Sandbox > File Access)
    • You are using the path/NSString based API of the directory enumerator instead of the URL NSURL based one.

    A vanilla Xcode project with Sandboxing enabled and the User selected files capabilities set, should enumerate any path obtained via NSOpenPanel:

    NSOpenPanel* panel =[NSOpenPanel openPanel];
    panel.canChooseDirectories = YES;
    [panel beginSheetModalForWindow:self.view.window completionHandler:^(NSInteger result) {
        NSFileManager *fileManager = [[NSFileManager alloc] init];
        NSURL *directoryURL = panel.URL;
        NSDirectoryEnumerator *enumerator = [fileManager
                                             enumeratorAtURL:directoryURL
                                             includingPropertiesForKeys:nil
                                             options:0
                                             errorHandler:nil];
        for (NSURL *url in enumerator) { 
            NSLog(@"url:%@", url);
        }
    }];
    

    If you want to store the ability to access specific folders from the sandbox across app launch/quit cycles, you will need to store a security scoped bookmark. This post contains information persisting user selected file/directory access via app scoped bookmark: Trouble creating Security-Scoped Bookmark