Skip to content

Issues with libPusher disconnects and the lock screen

rhussmann edited this page Apr 26, 2012 · 1 revision

Background

I've experienced, and seen several issues referencing, invalid libPusher connection state when dismissing applications to the lock screen (pressing the power button). See issues 17, 22, and 32.

Replication

This issues seems to manifest itself when -[PTPusher disconnect] is called before the app becomes inactive, (for instance from -applicationDidEnterBackground: or -applicationWillResignActive:.

In the app delegate, I've setup:

  1. -[PTPusher disconnect] in -applicationWillResignActive:
  2. -[PTPusher connect] in -applicationDidBecomeActive:
  3. Implemented the PTPusher delegate method -pusher:connection:didDisconnectWithError:

To exercise the issue,

  1. Launch the application
  2. Press the power button to background the app
  3. Repeat as necessary

On my iPad, after clicking the power button a few times, the PTPusher delegate method pusher:connection:didDisconnectWithError: will not be called when the app is backgrounded. At this point libPusher appears to be in a bad state that I've been unable to recover from.

Discussion

From my testing, it appears that the operating system is terminating the pusher disconnection mid-flight. To be fair, I don't think this is an issue with libPusher, but the responsibility of the application developer to ensure this call succeeds in some fashion.

The Fix

Fortunately, I've been able to handle this issue relatively easily. The application needs to request additional time for the -[PTPusher disconnect] call to complete. Here's the tail of my -applicationWillResignActive: method:

    __block UIBackgroundTaskIdentifier disconnectID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        [[UIApplication sharedApplication] endBackgroundTask:disconnectID];
    }];
    [self.pusherClient disconnect];

The code above requests additional time from the OS to finish computation. The expiration handler simply ensures the background task gets ended correctly. If a background task is not ended, iOS will terminate the entire application. The code above isn't entirely correct, as the background task should also be ended in -pusher:connection:didDisconnectWithError: (the success path). However, I'm keeping this brief to help highlight how to handle the workflow.

Side Effects

If you use this technique, I would suggest setting PTPuser.reconnectAutomatically = NO before disconnecting. Otherwise, in the remaining background execution time libPusher will attempt reconnection, which isn't really what I wanted as I was attempting to tear down the pusher connection.

Hope this helps others that may run into the issue.