I thought I’d take a minute and blog about what I learned, both so I remember the next time I want to do this, and because I didn’t find any resources out there that explained some of this, so I had to do trial-and-error on some of it. (Specifically, I only got one Google hit for “com.apple.security.temporary-exception.files.home-relative-path.read-only”, and that was the Sandboxing guide, which tells you what it’s for, but nothing about how to actually use it).
Turning on entitlements is pretty easy, just hit the “Enable Entitlements” checkbox on the project summary tab in Xcode 4.1.
Then hit ‘Build’ to make the Entitlements file, and as a bonus you get to find out if you have the right signing certificates set up to sign Mac apps (I didn’t, but that’s another post). Once you get your signing stuff set up and it builds once, you can open up the Entitlements file from the Project Navigator:
The first two things in this list were put in there automatically, because I checked “Enable App Sandboxing” and “Read/Write Access”.
Note 1: Once you check “Enable App Sandboxing”, then NSHomeDirectory() returns a sandbox directory instead of the user’s actual $HOME, which is a bummer for this App, because I need to interact with Dropbox, whose config files live under the users $HOME.
Note 2:The “user-selected.read-write” means that if you pop up an NSOpenPanel, that you are allowed to read and write whatever the user picks. However, if, like in this App, you expect to be able to access those files on later runs, you don’t appear to be able to.
[EDIT 2: OK, I’m told perserving access to user-selected files across app restarts is currently not supported. (thanks again to @radian)]
The second two keys of the PList were more complicated, and they’re the main reason I’m writing this.
- Note 3: The “temporary-exception.files.home-relative-path” stuff is one String per key of files in the user’s home directory that you need to read and/or write (depending on which option you pick). They
- begin with a slash("/") even though the are relative paths. Omitting the leading slash will cause them not to work. Second, they have to be files. You can’t stick a directory name there and expect to be able to write to it. You have to ennumerate, at compilation time, every file outside your sandbox that you want to read or write.
- You CAN put a directory here, but for it to work, you MUST add a trailing slash("/") to the directory name (thanks to @radian, reference here].
I like the idea of sandboxing, and I’ll try to use it on the Apps where it’s feasible. For trying to integrate with Dropbox, though, it’s just too impractical.
Hopefully, this post might save someone some time in trying to figure out how to create sandbox exceptions in their apps.