Using Growl in a sandboxed app

I am working on a new version of ShelfMenu and, to be able to release it on the Mac App Store, I had to adapt it to a sandboxed environment. ShelfMenu uses Growl for notifications, and I do not want to change this, especially since the new Growl framework works with OS X 10.6 onwards, gracefully falling back to the Notification Center on 10.8, if you do not have Growl running.

Growl expects its development framework, included in your application, to communicate with the Growl service using local networking. This is not allowed by default in a sandboxed application, unless you request specific entitlements (making it more challenging to get the app approved by Apple). So, if you don't need to add networking to your application, it's better to use an XPC service, as recommended in the Growl documentation. This is explained in the Growl documentation in a synthetic way, here is what you need to do in some more details.

As explained in the documentation, the best way to use an XPC service to communicate with Growl, is to take the XPC bundle provided in the Growl framework (which is already compiled), rename it, sign it with your developer certificate, and copy it into your app bundle. This XPC already includes the necessary entitlements.

If you download the latest Growl SDK (2.0 at the time of writing), you will need two things:

  • XPC Client/com.company.application.GNTPClientService.xpc
  • XPC Client/xpc-rename-move.rb

I have stored these items at the root of my application (one level above the Xcode project), where I keep all application assets (icons master files, graphics, and anything not needed by Xcode to build my project). This is the root level I commit to my SVC (git in case you wonder what I use).

In the screenshot, com.cemacsoft.ShelfMenu.GNTPClientService.xpc is created during the build process by a script (see below). You need not to worry about this.

Next you need to add a step to the compile process, in Xcode. Easier seen than explained, have a look at the following screenshot.

In step 4, the script comes from the Growl documentation, with a change to the location of the original XPC (com.company.application.GNTPClientService.xpc) to match my config; setting it to ".." as in the screenshot will work if you store the XPC one level above your project, as I did.

[shell]
XPC_START=".."
XPC_SCRIPT="$SRCROOT/../../scripts/xpc-rename-move.rb"
ruby "$XPC_SCRIPT" "$XPC_START" "$BUILT_PRODUCTS_DIR/$WRAPPER_NAME" "$CODE_SIGN_IDENTITY"
[/shell]

Hope this saves you some time.