Growl

Implementing Growl support in your Cocoa Application

Growl developer documentation


Let's Begin

This document is for Cocoa developers planning to implement Growl support in their application. In order to do this, you will need the following:

(Technically you can build without Xcode—but we're not going to cover that here.)

This document assumes that you have a working knowledge of Xcode, and that you have an already working application to which you would like to add Growl support.


Communicating with Growl

All your communication with Growl takes place through the Growl Application Bridge, using class methods declared in GrowlApplicationBridge.h. This does not just mean application-to-Growl communication (i.e., notifications); it also means Growl-to-application communication, such as click callbacks. We describe both later in this document.

The process is simple:

And if you want click feedback:

That's all there is to it!

Compatibility note

It actually is a bit more involved prior to Growl 0.7. If you want to support users who are running a version of Growl earlier than 0.7, you'll need to write a delegate even if you won't be handling click feedback. This delegate is responsible for supplying the registration dictionary that you would otherwise just put in your Resources folder.

A simple way to resolve this is to have a registration dictionary file in your Resources folder, and to implement the delegate by slurping that file and passing the contents back to the Bridge. You don't even need to check the version of Growl: This is harmless on 0.7, and not a performance problem unless you have a lot of notifications.

However, we recommend only supporting Growl 0.7 and later. This way, unless you want click feedback, all you need is the registration dictionary file—you don't need a delegate. Even if you do want click feedback, your delegate can implement only the click-feedback methods, without implementing the registration-dictionary method.


Registration

In order for Growl to know what notifications your application is able to post, you must register with Growl. This is very easy: simply write a registration dictionary, and place it in a file named “Growl Registration Ticket.growlRegDict” in your application bundle's Resources folder. This file must be in a property-list format, with a dictionary (obviously) as its root element.

When you provide your registration dictionary this way, Growl will detect it automatically when your program launches, by looking in your application's bundle. We call this auto-registration, in contrast to the manual registration that you can do either with a delegate (see next section) or by directly messaging the Growl Application Bridge.

Important: The search for the registration dictionary file is case-sensitive, even on case-insensitive file-systems. You must name the file exactly as shown above, or Growl will not notice it.

These are the keys that you must have in the dictionary:

TicketVersion

The version of the registration-dictionary format you're using. As of Growl 0.7 and 1.1, the current version is 1. The value should be expressed as an integer.

AllNotifications

An array containing the names of all the notifications that your application is able to post.

Other properties allow you to exert finer control over your registration with Growl. The most useful one is:

DefaultNotifications

An array containing the names of all the notifications that are enabled by default.

There are other keys, which will be listed at a future time.


The Growl Application Bridge delegate

Bug note: As of 1.1, the Growl Application Bridge requires a delegate to be set before you can use it—even if the delegate does not implement any delegate methods. As a workaround, use [GrowlApplicationBridge setGrowlDelegate:@""] to satisfy it.

You can designate an object within your application as responsible for providing Growl with the information it needs to register your application, display notifications, and pass information back to you if the user interacts with a Growl notification. This object must conform to the GrowlApplicationBridgeDelegate protocol.

@interface YourObjectController : NSObject <GrowlApplicationBridgeDelegate>

It may also implement one or more of the methods specified by the GrowlApplicationBridgeDelegate_InformalProtocol informal protocol.

To register, call

[GrowlApplicationBridge setGrowlDelegate:delegateObject];

delegateObject is the object that you want to be your Growl delegate. For basic usage (no click callbacks), you don't need a Growl delegate [see bug note above] you can simply set @"" as your delegate. If you do need a real delegate (e.g., for click callbacks), then in most implementations, you'll probably do this:

[GrowlApplicationBridge setGrowlDelegate:self];

Delegate methods

Since version 0.7 of the Growl frameworks, all of these methods are optional. They will only be called if implemented.

- (NSDictionary *) registrationDictionaryForGrowl;

The returned dictionary gives Growl the complete list of notifications this application will ever send, and it also specifies which notifications should be enabled by default. For most applications, these two arrays can be the same (if all sent notifications should be displayed by default). The NSString objects in these arrays are notification names, and thus will correspond to the notificationName: parameter passed into the +[GrowlApplicationBridge notifyWithTitle::::::::] calls.

The dictionary should have at least 2 key object pairs:

GROWL_NOTIFICATIONS_ALL
An NSArray of all possible names of notifications.
GROWL_NOTIFICATIONS_DEFAULT
An NSArray of notifications enabled by default (either by name, or by index into the GROWL_NOTIFICATIONS_ALL array).

These correspond to the AllNotifications and DefaultNotifications keys described above in “Registration”. All of the keys for registration dictionaries are defined in GrowlDefines.h.

Compatibility note: In versions of Growl before 0.7, this method is required, not optional.

- (NSString *) applicationNameForGrowl;

The name of your application. This name is used both for user display and for internal bookkeeping, so it should clearly identify your application (but it should not be your bundle identifier, because it will be displayed to the user) and it should not change between versions and incarnations (so don't include a version number or "Lite", "Pro", etc.). If this method is not implemented, the executable name specified by your application's Info.plist will be used. It is recommended that you implement this method.

- (NSData *) applicationIconDataForGrowl;

The delegate may return an NSData object to use as the application icon; if this is not implemented or returns nil, the application's own icon is used. This method is not generally needed.

- (void) growlIsReady;

Informs the delegate that Growl (specifically, the GrowlHelperApp) was launched successfully. The application can then take actions with the knowledge that Growl is installed and functional.

- (void) growlNotificationWasClicked:(id)clickContext;

Informs the delegate that a Growl notification was clicked. It is only sent for notifications sent with a non-nil clickContext, so if you want to receive a message when a notification is clicked, clickContext must not be nil when posting the notification. clickContext must be a property list: it must be a dictionary, array, string, data, or number object. Not all displays support click feedback.

- (void) growlNotificationTimedOut:(id)clickContext;

Informs the delegate that a Growl notification timed out. It is only sent for notifications sent with a non-nil clickContext, so if you want to receive a message when a notification timed out, clickContext must not be nil when posting the notification. clickContext must be a property list: it must be a dictionary, array, string, data, or number object. This selector was added in Growl 0.7.


Notification

Posting a notification with Growl is easy. One way is to use the following:

+[GrowlApplicationBridge
notifyWithTitle:(NSString *)title
description:(NSString *)description
notificationName:(NSString *)notificationName
iconData:(NSData *)iconData
priority:(signed int)priority
isSticky:(BOOL)isSticky
clickContext:(id)clickContext]

The arguments are as follows:

title

A title for this notification, such as “File transferred”. Required.

description

A description of the notification, which should provide more detail but should not flood the user with information.

Good description
“importantFile.zip (4.5 MB) transferred to Fortress.local in less than one second”
Bad description
“The file /Users/thisUser/desktop/importantFile.zip (4718592 bytes) was successfully transferred to Fortress.local in 0.00000143051147460938 seconds at an average of 3298534883328 bytes per second”

Required.

notificationName

A name for this notification. This must match a name which was in the GROWL_NOTIFICATIONS_ALL array in the dictionary returned by your delegate's registrationDictionaryForGrowl method. This name must be human readable, as it will be displayed in the Growl preferences pane. It will not, however, be displayed to the user when the notification is displayed. Required.

iconData

An NSData object which is a representation of an NSImage to be shown with this notification. If it is nil, the default icon for your application will be used. If you want the notification to have no icon, supply an empty NSData ([NSData data]). Optional.

priority

A signed integer value for the priority of this notification. The default value is 0; priority ranges from -2 (“Very Low”) to 2 (“Emergency”). The effect of different priority settings varies by Growl display plugin. Optional; pass 0 for no priority.

isSticky

If YES, the notification will remain on screen until clicked, if supported by the display plugin. The default behavior is for the notification to fade out after a delay. Optional; pass NO for the notification to behave normally, without “stickiness”.

clickContext

If the delegate implements the growlNotificationWasClicked: method (see above), this context will be passed back to the delegate if the notification is clicked. Optional; pass nil to not receive click notifications for this notification.

Another way is to use +[GrowlApplicationBridge notifyWithDictionary:] with an NSDictionary containing keys listed in Growl/GrowlDefines.h.

Other methods

Several other methods are made available by GrowlApplicationBridge, including methods for determining whether Growl is installed, determining whether Growl is running, and for re-registering with Growl if the notifications made available by your application change. These methods are not generally needed, so they are not explained in this tutorial. For more information, please see GrowlApplicationBridge.h.


Including and linking against the Growl framework

The recommended way to use the Growl framework is to link against it in your source folder, and copy it into your app bundle. This section tells you how to set up your Xcode project to do this.

There are two Growl frameworks available: Growl.framework and Growl-WithInstaller.framework. Everything described on this page applies equally to both. The only difference between the two is that Growl.framework will do nothing if Growl is not installed, whereas Growl-WithInstaller.framework includes a complete Growl installation and will, the first time your application attempts to display a Growl notification, prompt users of your application to install Growl if it is missing or update it if it is old. See GrowlApplicationBridge.h for optional delegate methods you can use to customize the information presented to the user when installing or upgrading.

For the rest of this document, we'll just say “the Growl framework”, and you should mentally replace this with the name of the framework you're using.

Also note that these steps apply equally well to a non-application bundle (such as a plug-in or another framework) as to an application bundle. They do not, however, apply to command-line applications. As of 0.6, the growlnotify extra (a command-line Growl client written in Cocoa) simply links in statically the GrowlApplicationBridge class from the Growl framework sources.

Finally, remember that right-click is emulated by control-click on a one-button mouse.

Note: Inclusion of Growl.framework in your application is required.

  1. Download the frameworks from the Downloads page from there.
  2. Copy the Growl framework to your application's project folder (or any subdirectory of it).
  3. Add the Growl framework to your project, making sure that all the relevant target checkboxes are checked. The header files in the framework use UTF-8 encoding.
  4. Add a Copy Files phase to your application's target.
  5. Get Info on the Copy Files phase.
  6. Set the destination to “Frameworks”, with no subpath (clear the field).
  7. Drag the framework from the group tree into the Copy Files phase.

From now on, your application will compile and link using the Growl framework inside its bundle.

If you are using the Growl framework from a loadable bundle on Mac OS X before 10.4, you have to load the framework dynamically from the bundle's Frameworks directory. This is because the dynamic linker resolves @executable_path to the path the of application that hosts your bundle, not the bundle's own path.

Using Cocoa, you can use the following code snipped to load the framework in your bundle:

NSBundle *myBundle = [NSBundle bundleForClass:[MyMainClass class]]; NSString *growlPath = [[myBundle privateFrameworksPath] stringByAppendingPathComponent:@"Growl.framework"]; NSBundle *growlBundle = [NSBundle bundleWithPath:growlPath]; if (growlBundle && [growlBundle load]) { // Register ourselves as a Growl delegate [GrowlApplicationBridge setGrowlDelegate:self]; } else { NSLog(@"Could not load Growl.framework"); }

If your application targets Mac OS X 10.4 or higher, you can use @loader_path instead of loading the bundle dynamically.

A previous version of this document gave instructions to set up the project so that Xcode would copy the framework first, then link against the copy. Subsequent tests have shown that the executable resulting from that procedure is identical to the executable resulting from the simpler procedure shown above. Thus the change.

Network Redux