2

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.

beeb
  • 1,187
  • 11
  • 32

2 Answers2

3

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

Community
  • 1
  • 1
Thomas Zoechling
  • 34,177
  • 3
  • 81
  • 112
  • Thanks for this, I managed to solve my problem by allowing read/write access to "user selected files" in the Xcode Sandboxing settings – beeb Nov 03 '15 at 09:45
1

It sounds like the current functionality will convert to Sandboxing just fine.

  1. The user selects the directory via NSOpenPanel (which will invoke something called Powerbox in the Sandboxed environment).
  2. This directory is now writable, as the user has explicitly selected it.
  3. You can even maintain write access to this directory by creating a Security Scoped Bookmark and storing it away between sessions.

This has got nothing at all to do with being Document based; that is an internal design that is unrelated to Sandboxing.

trojanfoe
  • 120,358
  • 21
  • 212
  • 242
  • Oh I see. Well actually I noticed that I can't even open a `NSOpenPanel` when I turn on sandboxing. Clicking on the button that usually opens the panel does nothing and raises an exception: `NSInternalInconsistencyException ... failed entitlements check`. – beeb Nov 03 '15 at 09:43
  • @beeb OK that sounds like you don't have something set-up property (from a project point-of-view). – trojanfoe Nov 03 '15 at 09:44
  • Never mind, I forgot to allow read/write access to user selected files in the sandboxing parameters! – beeb Nov 03 '15 at 09:45
  • 1
    Ah yes; that will do it. If you don't wish to persist access to a directory then there should be very little you need to change in the code itself. – trojanfoe Nov 03 '15 at 09:46
  • I will need to persist directory access since the path is stored in the user defaults and loaded upon start if the directory exists, but that's another story! Thanks – beeb Nov 03 '15 at 09:47