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.
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!
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.
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.
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];
Since version 0.7 of the Growl frameworks, all of these methods are optional. They will only be called if implemented.
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:
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.
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.
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.
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.
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.
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.
Posting a notification with Growl is easy. One way is to use the following:
The arguments are as follows:
A title for this notification, such as “File transferred”. Required.
A description of the notification, which should provide more detail but should not flood the user with information.
Required.
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.
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.
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.
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”.
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.
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.
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.
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.