Push Notifications—Device, Protocol and Server

3,862 views

Published on

Here are the slides from my presentation at the 2010 Apple University Consortium /dev/world conference.


Apple Push Notifications are an integral part of many applications, from games like "Words With Friends" to VOIP call notification, but for the non-expert developer they can be a source of mystery. Apple's "Local and Push Notification Programming Guide" provides details of the binary protocol, SSL certificates and other details which are hardly beginner material. Additionally the guide makes little mention of correct UTF encoding and other small details which create more difficulty for those unfamiliar with data encodings etc. And finally a persistent server is required which can handle the protocols. This talk will take attendees through: an understanding of the service overall; the protocol and its limitations; responding to notifications in the iOS application; approaches to implementing a server in Perl, Python or Ruby.

Bio:
Mark Aufflick has been involved in the Apple industry since his first job in 1995 and finally put his Computer Science degree to use becoming a freelance developer in 2000. Since then he has developed back end, web and gui applications for various Unix platforms, MacOS and iOS - for both corporate giants and small businesses. Mark has presented on programming topics in fora such as Sydney University's Web Engineering Group and CocoaHeads. These days Mark is an iOS and Mac developer with his company Pumptheory as well as the convenor of Sydney CocoaHeads.

Published in: Technology
1 Comment
5 Likes
Statistics
Notes
No Downloads
Views
Total views
3,862
On SlideShare
0
From Embeds
0
Number of Embeds
130
Actions
Shares
0
Downloads
94
Comments
1
Likes
5
Embeds 0
No embeds

No notes for slide




  • Note the device/Apple steps are simplified, eg. it is the device certificate, not the UDID, which is sent.


  • This is a binary format, so it needs some care


  • This is an interesting feedback loop since it’s the only way you can get insight into when someone uninstalls your app.


  • Remember the interaction diagram? - slide 5
  • Remember the interaction diagram? - slide 5
  • This is obviously just an example. Credit to Nathan de Vries for the compact conversion of token data into hex encoded string.

  • A subtle point - if your app is suspended in the background you won’t get this callback automatically - there will be a user dialog like if your app wasn’t running, but if the user taps View, your app will be brought to the foreground and then this message will be delivered as if your app was running at the time the notification was received.

    Also to add to the confusion, the displayed message wouldn’t ever be delivered to a background app because the action-loc-key = null means that there is no View button, only an OK button.
  • Take a quick mental break - we’ve now covered everything there is to know about establishing the app/device pair token and also everything there is to know about receiving notifications. Wasn’t too hard was it!

    Now we’re going to talk about sending notifications
  • • Remember the cert and private key are what you created with a combination of the dev portal wizard and Keychain Access.app.
    • The keychain app exports in .p12 format
    • the middle openssl command enforces a password for the certificate, hence the third step - of course use a password if you can
  • • Remember the cert and private key are what you created with a combination of the dev portal wizard and Keychain Access.app.
    • The keychain app exports in .p12 format
    • the middle openssl command enforces a password for the certificate, hence the third step - of course use a password if you can
  • You should all recognise the acronym TLS - Transport Layer Security - it’s basically the successor to SSL
  • We’re going to introduce the server side components with the Perl API. Partly because I wrote it, but also because compared to the Python server we will cover soon it is a more direct process to investigate.

    Remember the sound key here can refer to a sound file in your app bundle. In this case we have inline UTF-8, or we can use other keys to request an internationalised string - also already in your app bundle.

    Note that if you’re doing this on a Mac I recommend not modifying the system Perl installation since apps, for example Xcode, use the system Perl and expect it to behave a certain way - use MacPorts to install your own Perl installation instead.
  • SEGUE : if we have time, switch over to the implementation for a quick chat about pack()
  • You can see in this example we’re providing a password for the key. Best practice would be not to store the password in code, which is in your SCM, but instead to read it from a config file or, even better, some sort of memory only escrow service.

  • We’re setting a pretty frantic pace, so let’s grab our breath again. we’ve now covered everything there is to know about establishing the app/device pair token, everything there is to know about receiving notifications and everything there is to know about sending notifications and receiving feedback at the server end.

    The perl module we covered, and there are similar modules for other languages, is great if your server app already has, or you want to build, some kind of persistent, event driven process.

    If you don’t, there is a great python twisted-based server that you can use with python, ruby, or any other language for that matter.
  • We’re setting a pretty frantic pace, so let’s grab our breath again. we’ve now covered everything there is to know about establishing the app/device pair token, everything there is to know about receiving notifications and everything there is to know about sending notifications and receiving feedback at the server end.

    The perl module we covered, and there are similar modules for other languages, is great if your server app already has, or you want to build, some kind of persistent, event driven process.

    If you don’t, there is a great python twisted-based server that you can use with python, ruby, or any other language for that matter.
  • Like the Perl modules previously, if you’re doing this on a Mac I recommend using MacPorts to install your own python installation.

    Actually it’s a bit more work than shown the first time - you probably want to stick with python 2.6, you need to be careful to use the right easy_install script, the MacPorts twistd executable goes into /opt/local/Library/Frameworks/Python.framework/Versions/2.6/bin/twistd without a useful symlink, and you need to run twistd once as root to create some cache directories. Also for a high performance production server you want some twistd options to use epoll on linux or kqueue on MacOS. Send me an email or a tweet if you get stuck.

    You might wonder why there is no configuration - that’s one of the smart things about the pyapns server - it can handle APNS persistent connections on behalf of more than one app - when your app connects it registers an app_id and the relevant certificate and key files

    Obviously this should be run behind a firewall
  • Like the Perl modules previously, if you’re doing this on a Mac I recommend using MacPorts to install your own python installation.

    Actually it’s a bit more work than shown the first time - you probably want to stick with python 2.6, you need to be careful to use the right easy_install script, the MacPorts twistd executable goes into /opt/local/Library/Frameworks/Python.framework/Versions/2.6/bin/twistd without a useful symlink, and you need to run twistd once as root to create some cache directories. Also for a high performance production server you want some twistd options to use epoll on linux or kqueue on MacOS. Send me an email or a tweet if you get stuck.

    You might wonder why there is no configuration - that’s one of the smart things about the pyapns server - it can handle APNS persistent connections on behalf of more than one app - when your app connects it registers an app_id and the relevant certificate and key files

    Obviously this should be run behind a firewall
  • Also note the key and cert are concatenated into one .pem file here. The provision and notify functions don’t need to be called in the same process. Notify() can take a list of tokens and notifications dictionaries.

    Retrieving feedback data is similarly painless.
  • Now this is only a client for the pyapns server. Since all communication with the pyapns server is via XML-RPC it is client language agnostic.

    Notice the semantics for configure() are different to the python client.

    There are a few caveats with the current gem post Ruby 1.8.6 - you need to override the XMLRPC config variable as above, and you have to use the array style notification as above. These bugs are apparently fixed in the github trunk.

    In fact, I found out about pyapns when I was looking for ruby clients, because the majority of ruby APNS implementations do not maintain persistent connections - much like the state of the Perl implementations before I wrote mine.

    The one weakness is that you lose visibility on when Apple drops your connection which can give you a hint that a token is wrong. Mostly that shouldn’t happen though.


  • ×