Categories


Authors

Houston, We Have Apple Push Notifications

Houston, We Have Apple Push Notifications

“You’ve received a message from funnyguy718.” “Yet another person has RSVP’ed to your wedding.” “You have 24 hours to book your next hotel stay at a discount!”

Most mobile apps are exponentially more helpful if a user can enable push notifications. Implementing push notifications can seem tricky, but with the help of a gem called ‘houston’, it can be pretty straightforward. Using Rails as our backend, here’s a guide to how to setup Apple push notifications to iOS devices.

‘Houston’ is a Ruby gem developed by Matt Thompson that helps you send push notifications to Apple devices. In short, “Pass your credentials, construct your message, and send it.” Along with being fairly simple to implement, Houston allows testing of notifications from the command line and is easily configurable with your background job infrastructure of choice.  

Getting Started

To get started - like with any gem - add ‘houston’ to your Gemfile and run a ‘bundle install’.  ‘Houston’ requires a device_token in order to know to which device to send a push notification. If you don’t have a device_token in the database yet, you can either create a device model to store a user’s unique device token or you can add device_token to your existing user model. Either way, the attribute should be stored as a string. Run the migration.

class AddDeviceTokenToUser < ActiveRecord::Migration
  def change
    add_column :users, :device_token, :string
  end
end

Storing the Device Token

Now that your user has a device_token, you’ll need to save the token to the database at the relevant moment. This could be the moment when the user signs up, or when the mobile app calls an update API endpoint.

In our user’s controller, we can define this action:

def update
  current_user.update(device_token: device_token_param)
    if current_user.save
      render json: current_user, { status: "200" }, status: :ok
    else
      render json: { errors: current_user.errors.messages }, status: 400
    end
end

Configuring Parameters

Now that we are successfully storing a device token, we can set some configuration parameters for houston. The gem will load certain environment variables if they’re present, such as APN_CERTIFICATE. All options are listed in Houston’s documentation.

To begin, we create a new class called IOSPushNotification, and initialize the class with the user’s device token. We specify which Houston environment to use depending on the Rails environment, and identify the push certificate. The push certificate should be in .pem format, and separate certificates are required for development and production environments. You can provision these certificates using your iOS developer account.

class IOSPushNotification
  def initialize(device_token)
    @device_token = device_token
      @apn = if Rails.env.production? || Rails.env.staging?
               Houston::Client.production
             else
               Houston::Client.development
             end
      @apn.certificate = File.read('/path/apple_push_notification.pem')
  end
end

Be sure to move your APN certificate to your secrets.yml file. Note that after deployment you’ll have to SSH into each server to add the .pem file there as well. Also, if you’re using a CI build you may find it easier to set the certificate to nil when you’re in the test environment, as seen below.

def push_notification_pem_file
  Rails.env.test? ? nil: File.read(Rails.application.secrets.ios_push_certificate)
end

Creating A Push Notification

Once have defined the environment and certificate variables, we can actually create a notification, passing it the device_token with which we initialized the IOSPushNotification class.

@notification = Houston::Notification.new(device: device_token)
@notification.alert = "Hello, World!"

Enable Sending

The IOSPushNotification class requires one additional method - the one that actually sends the push notification. Check first that both a device_token and an APN certificate are present, and then send the notification!

def send_notification
  return unless @device_token && @apn.certificate
  @apn.push(@notification)
end

Customization

There are a few other customizations that we can make to your push notification, such as alert (i.e. “You’ve received a message!) and badge, which changes the badge count. You can also pass a sound, a category, and custom_data - such as sending the user_id of the message's sender. If using the above implementation, just make sure you initialize the IOSPushNotification class with any other elements you want, such as custom_data, and then set the custom_data just like we did with device token.

You can read more about all customizable options in Houston’s documentation.

Sending!

Lastly, we can define when we want to send our push notification; for example, within the “create” action of a message object. When sending, we can specify all of our customization.

def send_push_to_recipient(message)
  device_token = message.recipient.device_token
  alert = "You have received a message from #{message.sender.name}"
  push = IOSPushNotification.new(device_token, alert, sender_id: sender.id)
  push.send_notification
end

Testing

To test your push notifications from the command line, you can use the the APN push method with your device token as an argument.

$ apn push "<device_token>" -c /path/apple_push_notification.pem
  -m "Hello world, from the command line"

And to write tests for this functionality, you'll have to use a bit of stubbing. Be sure to include contexts for both the user having a stored device_token and missing one.

context "when user has a device token" do
  it "does send a push notification to message recipient" do
    allow(Message).to receive(:new).and_return(message)
    expect(IOSPushNotification).to receive(:new)
      .with(
        message.recipient.device_token,
        "You have received a message from #{message.sender.name}",
        message_id: message.id
      )
      .and_return(ios)
      expect(ios).to receive(:send_notification).once
      subject
  end
end

In Summary

Push notifications are a critical marketing tool for mobile apps, pulling your users back in when they are elsewhere and often vastly increasing engagement.  Setting up the backend for sending push notifications is much more straightforward with a little help from the Houston gem.

5 Lessons from My First Dev Job

5 Lessons from My First Dev Job

JSON Just As It Is

JSON Just As It Is