User Notifications in Depth

User Notifications in Depth

Talk given at /dev/world/2016 in Melbourne, Australia.


Sam Jarman

August 30, 2016


  1. /dev/world User Notifications in Depth Sam Jarman Sailthru NZ Aug

    29-31, 2016 @samjarman * Making apps for 6 years * Work with fortune 500 companies on setting up push and more daily * Obsessed with Push and getting it right
  2. Today • Conceptual Overview of User Notifications + iOS 10

    Changes • Implementation and Debugging • Best Practices for Notifications Today I want to cover 3 topics in Push Notifications and try go beyond what you’ll see in the WWDC videos. Too easy to regurgitate a keynote, so this will try to be something a bit different for more value. And lastly iOS drops next month, so let’s talk about that too!
  3. Conceptual Overview of User Notifications First up, let’s talk about

    notification concepts
  4. What Are They? First question, what are user notifications?

  5. User Notifications • Two types - Local and Remote •

    Both require permission • Both present the same way There are two types of notification Local & Remote When you’re asking for permission, you’re asking for permission for either. The notification is generally visually indistinguishable from the user.
  6. Local Notifications • Configured by developer • Time based triggers

    - Interval and Calendar • Location based triggers Local notifications are scheduled in code. They have to be thought about ahead of time in terms of structure and even content.
  7. Remote Notifications • A.K.A Push Notifications • Sent from a

    server • Processed by a OS + your app, delivered to user Remote notifications are the the usual suspects. Called push Notifications They are sent by a server at given time, and should be delivered shortly after. The OS processes it and does what it needs to to display it
  8. How Do They Look? So what do these notifications look

  9. Presentation Style • Alert • Badge • Sound Notifications typically

    show up as an alert. Optionally, an icon is badged, and a sound or vibration is played. We should be all familiar with these notifications from at least Messages or Mail.
  10. Platforms Platform Capabilities iOS Alert, Badge, Sound macOS Alert, Badge,

    Sound tvOS Badge watchOS Alert, Sounds CarPlay Sounds Safari Alerts, Custom Button Title While I’m talking about mainly push for iOS today, it’s not just iOS you can push to other platforms to.
 Obviously on iOS, you can get everything, as with macOS With TV you can badge the icon, such as to shown an unread or unwatched count On watchOS, you can get alerts and vibrations On Carplay, you can play sounds overtop of the music when a push arrives Safari can also receive alerts and set a custom open button title.
  11. What Can You Do? So what can you do with

    these notifications?
  12. Alerts • Localisable text • Fit to screen • Title,

    Subtitle • Localisation available Firstly and most typically you’d set some alert text. There’s not really a hard limit here for length, but its gonna fit on the screen. You can set a title and subtitle, and, if you have translations you can also send down a localization string. Even those with parameters an their values.
  13. Badge • 1-999,999,999,……. • Setting to 0 clears all alerts

    • No negative numbers You have the ability to set the badge. It can be an integer anywhere from 1 to INT MAX digits long… but dont. Use 6 at most.
 0 clears notifs for that app out of the tray
  14. Sounds • Must be included in the app bundle •

    .wav, .caf or .aiff file • < 30 seconds in duration afconvert /System/Library/Sounds/ Submarine.aiff ~/Desktop/sub.caf -d ima4 -f caff -v When a notification arrives, an optional sound can be played too. 
 Sounds must be included in the app bundle 30 seconds or less, otherwise they’re not played.
  15. Actions and Input • Configured when registering for user notifications

    • Different scenarios trigger different possible actions -“Categories” • Handled in your app iOS 8+ iOS 8 brought with it a concept of Actions. Actions are defined by the developer and are configured when registering for notifications. 
 Different scenarios trigger different possible actions. These scenarios are called “Categories” The user tapping the action kicks off a method in your app.
  16. Action Buttons • Configurable scenarios / “Categories” • Call into

    your app • May open your app • May indicate a destructive action • May require authentication iOS 8+ For example, the scenario of a new mail message could be a category of “new message”, with the actions of Mark as Read and Trash.
 Destructive means that some user data will be changed and not easily unchanged, for example, deleting an incoming email. This should be familiar as it’s red. You also get to define a minimal and default set, as some banners can show more than 2 actions at times. An extra possible action here is “Open Message”
  17. Text Input • A type of Action • Allow user

    to reply to type • Text is delivered to your app • iOS 10 allows for more control over the text input iOS 9+ iOS 9 bought with it the ability to reply in the actions. This was previously possible in Messages, but now any app can take register for notifications with actions that accept text. The text is delivered to your app as a string and you can do with it what you please. iOS 10 lets you define your own text input, allowing you to add accessories to the input. Speaking of iOS 10…
  18. iOS 10 Changes I originally thought of this talk before

    iOS 10 was announced. While I was happy with the features I’ve been describing, Apple gave us some cool new stuff.
  19. Big iOS 10 Changes • Revamped, enhanced API • Notification

    Service Extensions • Notification Content Extensions iOS 10 brings with it a completely revamped API, and two new extensions to deal with notifications too.
  20. Revamped UI • UN* classes (User Notifications) • Same concepts

    • Robust API iOS 10+ During the revamp, Apple replaced all the UIUserNotification classes with classes prefixed with UN. Overall, the same concepts I’ve described apply to the API, alerts, badges, sound, actions and categories, but now the API is a bit more sensible and robust - nice because lines up with UI
 The old API is deprecated so can be used, but you should like any deprecation start to move over.
  21. Notable Improvements • Manage remote notifications • Inspect responses -

    dismissed? • Control foreground appearance iOS 10+ You can now manage remote notifications, which you had almost no control over before. 
 You can find out whether a notification was dismissed - an interesting mechanism for A/B testing…or even AI. 
 You can now control some foreground appearance too. Neato.

  22. Notification Service Extensions • Called before the user is shown

    an alert • Chance to modify content • Download additional content iOS 10+ Notification service extensions are called before your alert is shown. It’s a great time to maximize the value of the content for your user. Perhaps you want to add a thumbnail or download a larger image, video or GIF for use inside the app. Perhaps you even want to decrypt the content of the push notification further. You then pass modified notify back
  23. Notification Content Extension • Create your own UI for an

    extension • Full storyboard access • Non-interactive • Format data in a readable, valuable way iOS 10+ Notification content extensions are activated when the user 3D touches on a notification (later betas may unlock long press too). 
 They allow you to create rich UI to display the push information. 
 They’re a view controller like any other, so you’re able to have a storyboard and layout as many UIElements as you like with auto-layout. 
 They are however read only, and cannot be interacts with. 
 This example here of the calendar is a simple example of how putting some push content in context of the rest of their day makes for a much more understandable and valuable notification. It’s pretty cool stuff and I encourage you to think about ways to visualize the data in your pushes to add value. 

  24. Learn More • Sessions 707, 708 - WWDC 2016 iOS

    10+ To learn more on iOS 10, check out sessions 707 and 708. 

  25. Conceptual Overview of User Notifications So that’s a conceptual overview

    of Notifications and the changes in iOS 10.
  26. Implementation and Debugging Next up, let’s talk about how we

    actually start setting some of this stuff up!
  27. Setting up Server Side The first part for any push

    notification is setting up the server side.
  28. Setting up Remote Push • Create/Edit App ID • Enable

    Push Notifications • Upload certificates • Generate new provisioning profile • Configure, build and run Setting up push is a tricky as heck thing to do! These are the abbreviated! steps to achieve this. So let’s walk through it.
  29. First up, you want to go and make you edit

    your App ID to enable push notifications. If you let Xcode manage your certs and provisioning this is a lot simpler. but I’ve never trusted that capabilities screen much.
  30. Go ahead and click create certificate

  31. This is done with Keychain access on the mac, and

    you just need to request a new certificate from a certificate authority. Sounds fancy. Really isn’t.
  32. Fill in the fields and save it to disk.

  33. and if that’s all too hard, the instructions are there

    again when you actually go to do this. Upload the certificate request file and you’re good to go.
  34. And then boom, your push certificate is ready.

  35. and at this point, you’d follow the instructions to upload

    it to your push service. Typically this involves exporting it out of keychain access with an optional password. This is what it looks like in the Carnival product. Your service should run some additional validation to tell you you’ve got it all right.
  36. Server Sent Push Device Server APNS Cert Token(s) + Content

    So here’s a diagram of how a service like this goes about getting a push to your device. They use tokens and the content and talk to Apple. Apple then works out which device it is and which app and tries to do the push via it’s persistent socket connection with each device.
  37. Setting up Client Side Moving on to how we set

    up client side
  38. Registering for Push • Alerts, Badges, Sounds • Categories •

    Remote? • Perform at a suitable time for your user (not just straight away) Now, you’ve added your new provisioning profile, you’ve tuned on the capabilities in Xcode, and you’re ready to go. 
 You need to set up your categories and their actions and then register the lot at once with he operating system. 
 You’ll also optionally register for remote notification, and you’ll get a token at this stage.
  39. Registering for push let settings = UIUserNotificationSettings(forTypes: [.Alert, .Sound, .Badge],

    categories: nil) UIApplication.sharedApplication().registerUserNotificationSetti ngs(settings) UIApplication.sharedApplication().registerForRemoteNotification s() This is the basic code to register for push. There’s some concepts here Types refer to alert, badge, sound categories are what we spoke about earlier, each with a set of actions. You can have multiple categories You register for the lot Then you additionally register for the push notifications. This API has changed slightly in iOS 10.
  40. Becoming Registered func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) { }

    func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) { } Once you register for push,
 One of these two methods will get called, and hopefully its not the fail case. 
 Devices always get tokens after registration, even if the user denies push. 
 Simulator will never get a token. Hand the token off to your server for push and you’re good to go!
  41. Server Sent Push Token Device Server APNS Cert Token(s) +

    Content And this is how it all works once you have the token handing off
  42. Running on Device • Notifications won’t work in the simulator

    • Need to use either development or production gateways • Production gateways require a production provisioning profile So, you’re up and running and you’ll notice that notifications don’t work in the iOS simulator The OS will register automatically for a given gateway based on the provisioning profile (distribution or development)
  43. In code func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject])

    { } func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) { } iOS <10 and the finally in here you’ll get the push. But only if your app is in the background (not restarted or swiped out of memory) There is an alternative method, that allows you to do background processing.
  44. Background Fetch • Prepare/Download content for user • “content-available”:1 •

    ~30 seconds to do something before alert is presented to user • Much more power in iOS 10+ This will call the didReceiveRemoteNotification with fetchCompletionHandler.
  45. Push Tools and The Remote Notification Payload Let’s talk about

    how you as a developer can use tools to send your own push, in development or even in production.
  46. APNS/2 The first tool I want to share is one

    called APNS/2
  47. Developed in house at Carnival, we use this in our

    infrastructure. It takes advantage of Apple’s new HTTP 2 interface and is written in Go for it’s really nice routines system and HTTP2 client.
  48. None
  49. You can just google “best push notifications” and the

    first non ad is this post. 

  50. APNS Payload { "aps" : { "alert" : { "title"

    : "Game Request", "body" : "Sam wants to play poker" }, "badge" : 1, "sound" : "gamerequest.wav", "category" : “GAME_REQUEST”, "content-available" : 1 }, "some_key" : "Some Value", "some_other_key" : [ "bang", "whiz" ] }
  51. Troubleshooting So push is great when it works, but it’s

    not always smooth sailing. Let’s talk about how you’d go about troubleshooting push, both during integration and ongoing.
  52. Common Pitfalls • Forgetting to regenerate provisioning profile after modifying

    app ID • Using the wrong APNS gateway • Using the “Fix Issue” button in Xcode. Just don’t. I deal with a lot of customers setting up put with our system, so I see the pitfalls a lot.
  53. Troubleshooting • Retracing your steps • Using TN2265 • Use

    Persistent Connection Logs For more troubleshooting, we often find a lot of success simply retracing your steps. There’s quite a few when setting up and it’s easy to miss them. 
 There’s also Tech Note 22 65 which describes a bunch more troubleshooting ideas, but really just gets you to trace your steps.
 The final way to really dig in deep is to use the persistent connection logs.
  54. Logging Apple maintains a persistent socket connection with APNS every

    time your phone is powered on. This logging profile when installed will log out everything going over that connection, as well as a bunch more logs from the OS. 
 To install, download it from the TN2265 and email to your phone. Restart the phone and you’re good to go.
  55. Log Messages Log Message Meaning Connected to courier Connected to

    APNS Disconnecting in response to connection failure. Your network has blocked APNS/ TCP Port 5223 connection set ignored topics The user chose to turn off notifications Failed to parse JSON message payload Server send malformed JSON Received message for enabled topic Log message for incoming push Once you’ve synced your phone with iTunes, or easier still, use the Xcode device log, you’ll be able to search for messages along these lines. This is super interesting stuff to see where things might be going wrong. For example, blocked ports, the users turned it off, or the server side has botched the JSON.
  56. 2016-08-13 14:47:01 +1200 apsd[100]: <APSCourier: 0x144e0d6c0>: Received message for enabled

    topic 'com.carnivalmobile.carnivaltestapp' with payload '{ "_nid" = 57ae8a248234f60009002e2f; aps = { alert = “Oh, Hi Mark!”; "content-available" = 1; }; }' onInterface: WWAN for device token: NO with priority (null) Here’s an example log message of a payload.
  57. Implementation and Debugging I wish you the best of luck

    with your implementation of push. It can be tricky but it’s just a matter of slowing down and making sure you’re checking those boxes. I’ve done this hundreds of times now so it’s second nature.
  58. Best Practices Finally today I wanted to bring it a

    little less technical and talk about best practices for remote notifications. I want to start with an important statement.
  59. Notifications go to people, not devices. @samjarman Notifications go to

    people, not devices. Remember this. People have good times to be contacted or interrupted, and they have terrible times. They might see your push and not care at all, or it might be something super important to them.
  60. 71% of app uninstalls are triggered by Push Notifications @samjarman

    Another important stat I heard recently is this. 71% of app uninstalls are triggered by Push Notifications.
 The good thing about notifications is they remind your users that your app is installed. A bad thing about notifications is they remind your users that your app is installed. Get that touchpoint wrong, and you’ve lost that user, perhaps for life. Usage, feedback and revenue are all gone. Bad push practices can really harm your bottom line.
  61. Make Them Timely So my first tip is make push

    notifications timely. And what I mean by this is to try predict the right time to contact your user. Can you be more flexible than just when you want?
  62. Respect Local Timezone Respect their timezone. It might be easy

    to say oh it’s 5pm here in Melbourne lets send out a push to all commuters, only to have your audience asleep in other parts of the world. If you have a sale or something, try send in the local timezone for the user. This will stagger the pushes over a window and might even reduce load on your server, if that’s required. A decent push service should give this this option.
  63. Respect Back-off Times Sometimes you might want to send multiple

    pushes per day, or different services that interact with your app with to inform the user. Consider having a hard limit on this. The limit is relative to the value, but something like a 5-10 max per day would suit most applications. Chat apps for example, won’t have a limit. 
 Consider also an internal priority for some notifications over the other.
  64. Respect Sleepy Time So yeah, sure, most people have their

    phones on do not disturb overnight, or at least on silent. But consider this… do you read all your notifications in the morning? or do you clear them all immediately maybe after reading the important ones? 
 If you’re part of that overnight noise, you have a lower chance of standing out. Perhaps restrict the amount of pushes you send over night and send a summary style push in the morning.
  65. Keep Them Relevant Next up, keep your pushes relevant.

  66. Don’t send content for anyone. Ultimately the most valuable pushes

    are the pushes for me. Chats, deals based on history, or news alerts based on preferences. Don’t send me junk and certainly don’t something that can’t apply to me, for whatever reasons.
  67. Personalize based on journey Carnival, and services like it, offer

    personalization based on journey. This could be anything to do with the context of the app. What level of the game you’re on, which items you have in your cart, which news stories you’ve read. How long you’ve had the app installed, or how long it’s been since you’ve last used it. There’s a bunch of marketing and engagement automation possible here off some basic stuff.
  68. Use transactional push Alternatively, but not mutually exclusively with audience

    segmentation is transitional push. These is the 1:1 pushes that go to a single users only. Perhaps their package is shipping, or they have a chat, or they’ve got a new like. These sorts of notifications are perfectly personalized by definition, but still adhere to the other best practices I’m talking about such as timeliness.
  69. Personalise with Names Use the persons name in a push,

    if you have it. “Sam, check out these new doctor who toys. Tap here”. Oh, and don’t say “click”.
  70. Use Precise Language Use precise language. Be obvious what you

    want. Make the call to action here. “You have a new chat from Ben”. “A new deal for you. Tap here for more” “Sam sent you a friend request”. You have no more than 10 words to make your impact. Use them wisely.
  71. Being a Good Citizen

  72. Ask for Permission Carefully That alert box that pops up

    after you register push may be one of the most important dialogs for your apps. 
 Preempt it. Onboard your user well. Explain “hey, here’s why we want to send you pushes and here’s what you get out of it. Keen?” If you explain the value before you present that alert, you’ll get a much higher opt in rate. We’ve seen rates go from 20-30% opt jump to 70-90% with these techniques. This also applies to all other dialogs such as location or bluetooth by the way.
  73. Use a 3rd party push service. Don’t try this yourself

    in production. Scaling. Reliability. Feedback. Etc etc. 
 Just use another service.
  74. Preload Content If your push drives a user to some

    in app content, you should really be pre-loading that with the available API first. This will delay the push by 20 seconds or so, but when they open the app, the UI should be ready to go. No one wants to be driven to a loading screen.
 Example: Facebook sometimes does this well.
  75. Duplicate Notifications Inside Your App Let’s be honest, it’s super

    easy to clear notifications. You should always try and duplicate the notification content inside the app. This could be an activity log, a chat history or a notifications log. Make it so users can always re-read the alert text of a notification.
 Example: Tweetbot’s activity screen
  76. Expose Settings If your app has different scenarios in which

    to send push, let the user turn off hearing about certain situations. 
 You can also use the notifications API to see which alerts they’ve enabled, and if they’ve denied you in past, you can always remind the users of the benefits (of which there should be some) of turning off push. Deep link them to the settings app and you’re done.
 Example: Swarm
  77. Have more? Medium post coming!
 Tweet me! - @samjarman Do

    you have any best practices? Tweet them to me as I’m compiling a list for a blog post soon.
  78. Conclusion • Conceptual Overview of User Notifications • Implementation and

    Debugging • Best Practices for Notifications So today you’ve heard about what notifications are, how to code them and how to use them for good and not evil.
  79. Thank You! " Sam Jarman • iOS Developer, Sailthru •

    @samjarman All images subject to copyright of their original owners. - I’ve been Sam Jarman, thank you very much. Enjoy the rest of the conference.