Sending Passbook Push Notifications with Houston and Sidekiq

The Nomad collection of iOS/Ruby tools are a great resource. I recently switched how Goldstar is sending out push notifications from Grocer to Houston.

Grocer has gone unmaintained for most of 2014, and it was obvious how to recover from a problem we were having with it where Apple would close the persistent connection we were using to send notifications, and so any notification sent after that would be lost. So I used Josh Symonds’ technique (with some tweaks I’ll mention later) to send them in a more robust way.

The one thing that Grocer does out of the box that Houston didn’t that we really needed was a way to send Passbook Push Notifications. These just like regular Push Notifications, however they are totally blank, sent to a token the pass registers with your server, and only work against the Production push notification gateway, using a different SSL certificate than your standard cert. This causes some problems because Houston assumes the Rails development environment should send pushes against the dev apple gateway.

So, what this means in reality is that you need 2 pools of persistent connections to apple’s gateway, and you need to override the gateway that Houston defaults to to be the production one only for the passbook updates.

Here’s the gist of the code I used:

class APNConnection

 def initialize(pem, uri)
 @uri = uri
 @certificate = File.read(pem)
 setup
 end

 def setup
 @connection = Houston::Connection.new(@uri, @certificate, nil)
 @connection.open
 end

 def write(data)
 begin
 raise "Connection is closed" unless @connection.open?
 @connection.write(data)
 rescue Exception => e
 attempts ||= 0
 attempts += 1

 if attempts < 5
 setup
 retry
 else
 raise e
 end
 end
 end

 def method_missing(m, *args, &block) 
 @connection.send(m, *args)
 end 

end

Then, in an initializer, I set it up like this:

$APN_POOL = ConnectionPool.new(:size => 2, :timeout => 300) do
 uri = Rails.env.production?? Houston::APPLE_PRODUCTION_GATEWAY_URI : Houston::APPLE_DEVELOPMENT_GATEWAY_URI
 APNConnection.new(GOLDSTAR_PEM_PATH, uri)
end
$PASSBOOK_POOL = ConnectionPool.new(:size => 2, :timeout => 300) do
 APNConnection.new(GOLDSTAR_PASSBOOK_PEM_PATH, Houston::APPLE_PRODUCTION_GATEWAY_URI)
end

Now we have two pools and the passbook push notifications are only using the production gateway. Notice we’re using two different PEM files. The PASSBOOK_PEM file I’m using is taken from the “Pass Type IDs” section of the Apple developer site. Download and convert to PEM just like you would a regular push notification certificate. It’s also the same certificate you’re signing your passes with.

Apple Developer Site

Finally, we need to construct a notification.

notification = Houston::Notification.new(device: registration.push_token)
 $PASSBOOK_POOL.with do |conn|
 conn.write notification.message
 end

The important part of this code is that the “device” we’re sending this to is not actually a device token, like a regular push notification, but instead the pushToken that comes over when a passbook pass registers with your web service.

And that’s it.You should now be able to send both push notifications and passbook push notifications in the same app.