Pushing events to your iPhone using WebSockets and Pusher

22 March 2010 Pushing events to your iPhone using WebSockets and Pusher

Earlier today, New Bamboo announced their new Pusher service. Pusher is a centralized service that allows you to distribute real-time events from your web apps to the browser using HTML5 WebSockets.

It immediately struck me: why limit yourself to the browser? What if your iPhone (or iPad) app could receive those events too? Sure, you could use the Apple Push Notification Service, but why go through all the hassle that entails just to send events from your server?

If you could use the same event-distribution mechanism for your real-time HTML5 browser interface as your iPhone/iPad (or any other) interface, that's an instant win.

Getting started with the Pusher Objective-C client

So, with just the existing Javascript reference client to go on, I set about trying to create an Objective-C client. I've tried to mirror the Javascript API where it makes sense, but using a more Cocoa-centric approach (e.g. target/selector binding and notifications).

Using the library is fairly straightforward and there are principally two ways of using it, which I'll explain here. If you haven't already, you might want to read up on how Pusher works.

First of all, you need to create an instance of PTPusher for the channel you want to monitor.

- (void)applicationDidFinishLaunching:(UIApplication *)application {
  // pusher is an instance variable in my app delegate
  pusher = [[PTPusher alloc] initWithKey:@"YOUR_API_KEY" 
                                 channel:@"THE_CHANNEL_NAME"];
}

Once you have a PTPusher instance, you can start registering for events. Each event listener requires a target and a selector.

[pusher addEventListener:@"my-event" 
  target:self selector:@selector(handleEvent:)];

The event callback method will receive a single argument, the PTPusherEvent object representing the event. Here's what handleEvent: might look like:

- (void)handleEvent:(PTPusherEvent *)event;
{
  // lets just log the event name and data
  NSLog(@"Received event %@, data: %@", event.name, event.data);
}

As you can see, PTPusherEvent has two properties: name and data. The data property will return the deserialized JSON data as a native Objective-C object, typically an NSDictionary.

The second approach is to use notifications. Whenever PTPusher receives an event, it will post a PTPusherEventReceivedNotification. This will allow you to respond to events across your application without necessarily knowing about a specific PTPusher instance:

// register for event received events
[[NSNotificationCenter defaultCenter] addObserver:self
  selector:@selector(handlePusherEvent:)
      name:PTPusherEventReceivedNotification
    object:nil];

In your notification handler, you will be able to get the PTPusherEvent from the NSNotification's object property.

Because your notification handler might not know anything about the PTPusher that sent it, you might want to check the channel from which the event arrived before deciding how to handle it. You can do this by using the channel property of PTPusherEvent.

- (void)handlePusherEvent:(NSNotification *)note;
{
  PTPusherEvent *event = note.object;
  if([event.channel isEqualToString:@"some_channel"]) {
    NSLog(@"Received event %@, data: %@", event.name, event.data); 
  }
}

Obviously, both Pusher and the Objective-C client are still in their early stages. There is still some work to be done with the client, including proper error handling, but there's a lot of potential to create some interesting, cool applications using this. I already have some plans to integrate it with the work I've been doing on synching web services with Core Data.

I've recorded a small screencast that shows the library in action. Grab yourself a Pusher account and API key and have a play. As always, the code is available on GitHub.