1
votes

I'm writing an OS X sandboxed application. It recieves @3x and @2x image files and transforms them into lower resolution images. I'm getting the image URLs by either the files being dragged into the app window or a directory being chosen using NSOpenPanel.

Once the images are dragged or the folder is selected, I run a for loop and resize each image using this method

-(BOOL)writeImage:(NSImage*)image toFile:(NSString*)file withRepresentation:(NSString*)extension{

CGImageRef cgRef = [image CGImageForProposedRect:NULL
                                         context:nil
                                           hints:nil];
NSBitmapImageRep *newRep = [[NSBitmapImageRep alloc] initWithCGImage:cgRef];
[newRep setSize:[image size]];
NSData *pngData = [newRep representationUsingType:[self getRepresentationType:extension] properties:nil];
return [pngData writeToFile:[file stringByAppendingString:[NSString stringWithFormat:@".%@",extension]] atomically:YES];

This breaks the sandbox model. I've read I should be using NSSavePanel, but this would require me to specify the final filepath/filename for each of the saved images, which ruins the user experience.

Is there any way to ask the sandboxed app permision to write to certain directory instead of asking permission to write each file?

1
Ask a search engine about security-scoped bookmarks.El Tomato
maybe you have other reasons for doing this, but you could just use automator to do batch image resizing...Fonix

1 Answers

3
votes

Yes, you can easily ask for permission to write to a certain directory.

You already know how to use NSOpenPanel to allow the user to select a directory - "or a directory being chosen using NSOpenPanel". When the user does that you get read/write permission on the directory, so you can read a file [email protected] and write one named [email protected] etc.

Now in addition to being able to use NSOpenPanel to select a directory you can also:

  1. specify delegate methods to determine which items should be enabled for the user to select, and to determine if a user selected item is acceptable;

  2. set the directory which is first displayed when the NSOpenPanel dialog is opened; and

  3. set prompt messages and button labels in the NSOpenPanel dialog.

Combining these features you can present a dialog which asks the user to confirm access to a specific directory:

  1. set the prompt to something like "Please confirm access to directory";

  2. set the label on the "Open" button to something like "Confirm";

  3. set the initial directory to the parent of the directory you are after; and

  4. use the delegate methods to only allow the user to either choose the directory to cancel.

Bundle that up as, say, MyConfirmDirectoryPanel.

Now when the user presents you with a file:

  1. Determine the directory of that file

  2. Check whether you have write access to the directory using the access() system call - see section 2 of the "Unix" manual (just search for access in Xcode's documentation). If you have write access go to (4).

  3. If you don't have access use your MyConfirmDirectoryPanel to have the user select the directory, thus granting you access.

  4. You now have write permission on the directory, go ahead and create your scaled image file.

The access you gain in this way will last for the remaining execution of your app; so if, for example, your user then selects another file in the same directory you won't have to ask for permission again. If you want to preserve the access between executions of your app you can do that as well. You this this using a security scoped bookmark, look up the documentation of those. Using that mechanism you can create a cache of saved bookmarks - storing them say in your user defaults - which you can activate as needed to regain access to directories previously granted to you by the user. If you do this over time the number of times you have to explicitly ask the user for permission will dwindle and your user will get the UI experience they expect - drag a file, resized imaged created next to it in same directory.

HTH