Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
An Objective-C interface to Pusher (
tag: v1.2

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.
Functional Specs
Unit Tests

libPusher, an Objective-C client for Pusher

Pusher is a hosted service that sits between your web application and the browser that lets you deliver events in real-time using HTML5 WebSockets.

This project was borne out of the idea that a web browser doesn't have to be the only client that receives your web app's real-time notifications. Why couldn't your iPhone, iPad or Mac OSX app receive real-time notifications either?

Apple provides its own push notification service which is great for getting alert-type notifications to your app's users whether or not they are using the app, but for real-time updates to data whilst they are using your app, hooking into your web app's existing event-dispatch mechanism is far less hassle (and is great if you want to be able to interact with other web services that might not have access to the APNS).

Latest Release: 1.2 (29 Feb 2012)

  • Changed backend socket library to SocketRocket
  • PTPusherEvent objects have a timeReceived property.
  • Updated to the latest version of JSONKit.
  • Re-added armv6 archicture for iOS 4.0 - 4.2 support.
  • HTTP authorization for private/presence channels now accepts a HTTP 201 status as well as 200 (#23).
  • Fixed triggering of client events (would previously send the channel name as the event name).
  • Fixed retain cycle between PTPusher and PTPusherChannel.
  • OSX framework is now called Pusher.framework.
  • Project has been converted to use ARC (Automatic Reference Counting).
  • All event binding methods return a PTPusherEventBinding object, which can be used to remove bindings (see "Removing Bindings" below).
  • Channels should be removed from the cache when they are unsubscribed (#25).
  • Subscribing to multiple private channels would fail as only the first channel would send the authorization request (#26).
  • Wait for handshake and socket ID to be received before attempting to connect to channels as the socket ID is required for private/presence channel authorization.

Update Note: 1.0 (August 2011)

A large update was made to this library in August 2011 that is not backwards compatible with previous-versions of this library. Users are advised to take the time to update their code to use the new API, which now mirrors more closely the Pusher Javascript API and will be more stable going forwards.

The major changes are:

  • Re-architected the core API to bring it in line with the Javascript API.
  • Support multiple channels over a single connection.
  • Added support for private and presence channels.
  • Added block-support for event callbacks.
  • Extracted the wrapper for the Pusher REST API into a standalone component.
  • Dropped support for iOS 3.0

Installation instructions

Detailed installation instructions can be found in the wiki.

Getting started

The libPusher API mirrors the Pusher Javascript client as closely as possible, with some allowances for Objective-C conventions. In particular, whilst the Javascript client uses event binding for all event handling, where events are pre-defined, libPusher uses the standard Cocoa delegation pattern.

Online API Documentation

Creating a new connection

PTPusher *client = [PTPusher pusherWithKey:@"YOUR-API-KEY" delegate:self];

When calling the above method, the connection will be established immediately. If you want to defer connection, you can do so:

PTPusher *client = [PTPusher pusherWithKey:@"YOUR-API-KEY" connectAutomatically:NO];

When you are ready to connect:

[client connect]

It is recommend you assign a delegate to the Pusher client as this will enable you to be notified when significant connection events happen such as connection errors, disconnects and retries.

Binding to events

Once you have created an instance of the Pusher client, you can set up event bindings; there is no need to wait for the connection to be established.

When you bind to events on the client, you will receive all events with that name, regardless of the channel from which they originated.

There are two ways of creating bindings to events. You can bind to events using the standard target/action mechanism:

[client bindToEventNamed:@"something-happened" target:self action:@selector(handleEvent:)];

Or you can bind to events using blocks:

[client bindToEventNamed:@"something-happened" handleWithBlock:^(PTPusherEvent *event) {
  // do something with event

Removing bindings

Prior to 1.2, there was no way of removing bindings. This resulted in a potential memory issue as when a binding was created a special event listener object was created internally which would, in the case of target/action bindings, retain the target. There was no way of getting at this listener object - the listener was retained by the event dispatcher of either the PTPusherChannel or PTPusher instance that you had binded to.

In 1.2, the way listeners were retained was changed. Now, each binding creates a PTPusherEventBinding object and it is this object that retains the event listener object and the event dispatcher would retain a collection of binding objects instead. Additionally, all binding methods now return the PTPusherEventBinding instance, which means an object can keep track of all of it's bindings and remove them at a later date (for instance, in dealloc).

Removing a binding is as simple as storing a reference to the binding object, then passing that as an argument to removeBinding: some time later.

- (void)viewDidLoad 
  self.myControllerBinding = [client bindToEventNamed:@"some-event" target:self action:@selector(handleSomeEvent:)];

- (void)dealloc 
  if(self.myControllerBinding) {
    [client removeBinding:self.myControllerBinding];

Working with channels

Channels are a way of filtering the events you want your application to receive. In addition, private and presence channels can be used to control access to events and in the case of presence channels, see who else is subscribing to events. For more information on channels, see the Pusher documentation.

Subscribing and unsubscribing

Channels of any type can be subscribed to using the method subscribeToChannelNamed:. When subscribing to private or presence channels, it's important to remember to add the appropriate channel name prefix.

You do not need to wait for the client to establish a connection before subscribing; you can subscribe immediately and any subscriptions will be created once the connection has connected.

Subscribing to a public channel:

PTPusherChannel *channel = [client subscribeToChannelNamed:@"my-public-channel"];

Subscribing to a private channel using the appropriate prefix:

PTPusherChannel *private = [client subscribeToChannelNamed:@"private-channel"];

As a convenience, two methods are provided specifically for subscribing to private and presence channels. These methods will add the appropriate prefix to the channel name for you and return a channel cast to the correct PTPusherChannel sub-class. You can also set a presence delegate for presence channels using this API.

Subcribing to a private channel without the prefix:

PTPusherPrivateChannel *private = [client subscribeToPrivateChannelNamed:@"demo"];

Subscribing to a presence channel without the prefix, with a presence delegate:

PTPusherPresenceChannel *presence = [client subscribeToPresenceChannelNamed:@"chat" delegate:self];

Any channel that has been previously subscribed to can be retrieved (without re-subscribing) using the channelNamed: method.

PTPusherChannel *channel = [client channelNamed:@"my-channel"];

You can also unsubcribe from channels:

[client unsubscribeFromChannel:channel];

Channel authorisation

Private and presence channels require server-side authorisation before they can connect. Because the Javascript client library runs in the browser, it assumes the presence of an existing server-side session and simply makes an AJAX POST to the server. The server then uses the existing server session cookie to authorise the subscription request.

When using libPusher in your iOS apps, there is no existing session, so you will need an alternative means of authenticating a user; possible means of authentication could be HTTP Basic Authentication or some kind of token-based authentication.

In order to connect to a private or presence channel, you first need to configure your server authorisation URL.

pusher.authorizationURL = [NSURL URLWithString:@""];

When you attempt to connect to a private or presence channel, libPusher will make a form-encoded POST request to the above URL, passing along the socket ID and channel name as parameters. Prior to sending the request, the Pusher delegate will be notified, passing in the NSMutableURLRequest instance that will be sent.

It's at this point that you can configure the request to handle whatever authentication mechanism you are using. In this example, we simply set a custom header with a token which the server will use to authenticate the user before proceeding with authorisation.

- (void)pusher:(PTPusher *)pusher willAuthorizeChannelWithRequest:(NSMutableURLRequest *)request
  [request setValue:@"some-authentication-token" forHTTPHeaderField:@"X-MyCustom-AuthTokenHeader"];

Binding to channel events

Binding to events on channels works in exactly the same way as binding to client events; the only difference is that you will only receive events with that are associated with that channel.

PTPusherChannel *channel = [client subscribeToChannelNamed:@"demo"];

[channel bindToEventNamed:@"channel-event" handleWithBlock:^(PTPusherEvent *channelEvent) {
  // do something with channel event

Binding to all events

Unlike the Javascript client, libPusher does not provide an explicit API for binding to all events from a client or channel. Instead, libPusher will publish a NSNotification for every event received. You can subscribe to all events for a client or channel by adding a notification observer.

Binding to all events using NSNotificationCentre:

[[NSNotificationCenter defaultCenter] 

Bind to all events on a single channel:

PTPusherChannel *channel = [client channelNamed:@"some-channel"];

[[NSNotificationCenter defaultCenter] 

The event can be retrieved in your callback from the notification's userInfo dictionary. The notification's object will be either the client or channel from which the event originated.

- (void)didReceiveEventNotification:(NSNotification *)note
  PTPusherEvent *event = [note.userInfo objectForKey:PTPusherEventUserInfoKey];

Handling network connectivity errors and disconnects

The nature of a mobile device is that connections will come and go. There are a number of things you can do do ensure that your Pusher connection remains active for as long as you have a network connection and reconnects after network connectivity has been re-established.

The following examples use Apple's Reachability class (version 2.2) to check the network reachability status. Apple recommends that in most circumstances, you do not do any pre-flight checks and simply try and open a connection. This example follows this advice.

You can configure libPusher to automatically try and re-connect if it disconnects or it initially fails to connect.

PTPusher *client = [PTPusher pusherWithKey:@"YOUR-API-KEY" delegate:self];
client.reconnectAutomatically = YES;
client.reconnectDelay = 30; // defaults to 5 seconds

What you don't want to do is keep on blindly trying to reconnect if there is no available network and therefore no possible way a connection could be successful. You should implement the PTPusherDelegate methods pusher:connectionDidDisconnect: and pusher:connection:didFailWithError:.

- (void)pusher:(PTPusher *)client connectionDidDisconnect:(PTPusherConnection *)connection
  Reachability *reachability = [Reachability reachabilityForInternetConnection];

  if ([reachability currentReachabilityStatus] == NotReachable) {
    // there is no point in trying to reconnect at this point
    client.reconnectAutomatically = NO;

    // start observing the reachability status to see when we come back online
    [[NSNotificationCenter defaultCenter] 

    [reachability startNotifier];

The implementation of pusher:connection:didFailWithError: will look similar to the above although you may wish to do some further checking of the error.

Now you simply need to wait for the network to become reachable again; it's no guarantee that you will be able to establish a connection but it is an indicator that it would be reasonable to try again.

- (void)reachabilityChanged:(NSNotification *)note
  Reachability *reachability = note.object;

  if ([reachability currentReachabilityStatus] != NotReachable) {
    // we seem to have some kind of network reachability, so try again
    PTPusher *pusher = <# get the pusher instance #>
    [pusher connect];

    // we can stop observing reachability changes now
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [reachability stopNotifier];

    // re-enable auto-reconnect
    pusher.reconnectAutomatically = YES;

Finally, you may prefer to not turn on automatic reconnection immediately, but instead wait until you've successfully connected. You could do this by implementing the pusher:connectionDidConnect: delegate method:

- (void)pusher:(PTPusher *)client connectionDidConnect:(PTPusherConnection *)connection
  client.reconnectAutomatically = YES;

Doing it this way means you do not need to re-enable auto-reconnect in your Reachability notification handler as it will happen automatically once you have connected.

If Pusher disconnects but Reachability indicates that the network is reachable, it is possible that there is a problem with the Pusher service. In this situation, you would be advised to simply allow libPusher to try and reconnect automatically (if you have enabled this).

You may want to implement the pusher:connectionWillReconnect:afterDelay: delegate method and keep track of the number of retry attempts and gradually back off your retry attempts by increasing the reconnect delay after a number of retry attempts have failed. This stops you from constantly trying to connect to Pusher while it is experience issues.


PusherTouch uses the ZTWebSocket library by OpenResearch, without which I probably wouldn't have got anywhere.

For more information about Pusher, visit the website.


All code is licensed under the MIT license. See the LICENSE file for more details.

Something went wrong with that request. Please try again.