Sending Passbook Push Notifications with Houston and Sidekiq
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.
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.