Setting up APNS for iOS

Last week we started setting up push notifications on the iOS app we are building at work. I knew from my time at QuizUp that this is more complicated than you’d think, but still I was surprised at the complexity Apple front-loads on people developing for their platforms.

I read a couple of guides which were either slightly too vague, or really detailed but contained directions for outdated versions of one of the many graphical user interfaces Apple seems to think developers enjoy (hint: most of us do not!).

First I attempted what I usually do: to understand what I am doing before committing to any potentially confusing changes. After spending some time with this layercake of cryptographic overengineering I abandoned hope of abstract understanding and decided to learn by doing.

Thirty hours later I was left with a whole bunch of useless keys, certificates, provisioning profiles, app ID’s and various unspeakable things done to my local keychain and our iOS “Certificates, Identifiers & Profiles” in the Apple Developer Center. But I ended up with these steps here.

I was helped a lot by this excellent guide by Ray Wenderlich. I pretty much followed his steps, but use the openssl command line tool instead of Apple’s “Certificate Assistant”.

So without further ado, here are the steps I followed:

  1. In your terminal of choice, Generate private key

        openssl genrsa -out com.example.app.key 2048
    

  2. In that same terminal, create a CSR (Certificate Signing Request)

    $ openssl req -new \
      -key com.example.app.key \
      -out com.example.app.csr \
      -subj "/emailAddress=you@example.com/CN=com.example.app/C=IS/O=Example Ltd"
    
    I recommend keeping these two files somewhere safe, you’ll need them in step 5.

  3. Log into the Apple Developer console. Go to “Certificates, Identifiers & Profiles”, and create a new App ID, I’ll use com.example.app for this guide.

  4. Again in the Apple Developer console, Click “Edit” under “Application Services”, and scroll down to “Push Notifications”, click there “Create Certificate”. Use the CSR created earlier (com.example.app.csr) to create the certificate, download it, it will have a filename like aps_development.cer.

  5. Convert the .cer file into a PEM file:

       openssl x509 -in aps_development.cer -inform der -out com.example.app.aps_developement.pem
    

  6. Test your key and certificate against APNS:

    $ openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert com.example.app.aps_developement.pem -key com.example.app.key
    
    If everything is OK, you should see a “CONNECTED..” string, followed by a succesful SSL handshake. You can stop by sending EOF (^D).

  7. Combine the private key and the aps_development certificate into a single PEM file:

    $ cat com.example.app.key com.example.app.aps_developement.pem >> apns_com.example.app_combined.pem
    
    You will use this file later when sending notifications.

  8. Go into the Apple Developer Console, open “Provisioning Profiles” click the “+” icon. There choose “iOS Development”, then click continue. There choose the App ID created earlier (com.example.app) and click continue. Then choose the developer certificates and the devices, finally click “generate”. Choose a name for the profile and then download it.

  9. Once you’ve downloaded your profile (should have a .mobileprovision suffix) drag it into XCode, or open it in XCode somehow.

Now what you do with the provisioning profile is something I’ll leave to my colleague Trausti to explain, since he wrote the client code. Until then you can check out Ray’s guide I mentioned here above, and figure out how to get your very own device token.

Once you’ve gotten your device token for your app using the same bundle identifier as you used in my steps above (com.example.app) you’ll want to test it. Since I’m mostly using python these days, and Ray’s example was in PHP (which works fine btw!), I decided to implement an APNS test script in python: apnsend.

$ git clone git@github.com:steinnes/apnsend.git
$ cd apnsend
$ make 
$ venv/bin/apnsend apns_com.example.app_combined.pem token "hello from apnsend" -s

The script takes as a parameter the PEM file containing your key and the certificate generated by apple, and a device token requested from an app with the bundle id, which was built using the provisioning profile.

The end result should look something like this:

First push notification

Later article
Flask and StatsD