Try swift nyc craig clayton header

Creating Rich Custom UI Notifications

In this talk, Craig Clayton covers how you can build a unique user experience using custom UI for notifications, in particular, how he created a custom experience for NFL teams to use year round for fan engagement.

Today we’re going to look how notifications are handled in iOS 10, and cover iOS 11 features. Finally, I’m going to show you how - in the sports environment - we can engage users throughout the entire year.

Setting Up Notifications

-application: didRegisterForRemoteNotifications...:
-userNotificationCenter: willPresent: completionHandler:
-userNotificationCenter: didReceive: completionHandler:

These are the three basic methods that we need to use.

didRegisterForRemoteNotifications, is used to check whether the device has received permissions. If there was no permission, we ask the user for permission to send notifications, then we can access the device token.

The next method to implement is willPresent. willPresent is called when the app is in the foreground. didReceive is called when the notification is delivered to the user. Those are the three basic methods you need to get started with from iOS 10 and 11.

Basic Notifications

    "aps": {
      "alert": {
        "title": "Keys to the Starting...",
        "subtitle": "Presented by CarMax",
        "body": "Saturday night Bill..."
      "badge": 0

Get more development news like this

Here’s what an iOS notification in JSON looks like. We have a dictionary of aps that has the alert, title, subtitle, body. Everything is encapsulated in this dictionary.

Notifications with Images

In iOS 10, this was a feature that was not commonly used. You add a URL to attach images to the notifications.

  "aps" : {
    "alert": "New Message",
    "mutable-content" : 1,
    "sound": "default"
    "badge": 0
  "title": "Keys to the Starting...",
  "subtitle": "Presented by CarMax",
  "body": "Saturday night Bill...",
  "url": "image-url-here.jpg"

The main key to this JSON is we have mutable content set to 1. This tells Apple that we want to use our own content here.

We push all the data that we want to display outside of the aps because we’re not going to actually show it.

  currentDownloadTask = URLSession.shared.downloadTask(with: url, completionHandler: { fileURL, _, error in
      if let error = error { ... }


Then, we create a service extension to use an URL session, which allows us to download our image into our app.

  if let fileURL = fileURL,
      mutableContent.attachments = [attachment]
      mutableContent.title = title
      mutableContent.subtitle = subtitle
      mutableContent.body = body

Finally, we set some attachments: the title, the body, and the subtitle.

iOS 11 Features

Let’s go over the iOS 11 features: hidden content, combining notifications, customizing rich notifications. We’ll review how we can use these features.

Hidden Notification Content

Hidden content is new to iOS 11. Users can now go into their settings and turn notification previews off. This means that users only see the text “notification”, as opposed to the substantive notification contents.

  let scoreCategory = UNNotificationCategory(
    identifier: "score-category",
    actions: [],
    intentIdentifiers: [],
    hiddenPreviewsBodyPlaceholder: NSLocalizedString("SCORE_CATEGORY",
      comment: "score placeholder"),
      options: [])

First, we need to do is create a category. Our category can be for anything - articles, scores, etc.

CraigClayton HiddenContentPList

Finally, we create a plist for localization. We add this to our notifications, and instead of just getting notifications, we can get a “score”, an “article”, or a “video” which gives some context to the user.

Combining Notifications

What happens if we have multiple notifications from different categories and want to combine those together? You don’t want to put everything in one notification when one category is a “score” and another is an “article”.

  { "aps": {
      "alert": "New Message",
      "sound": "default",
      "thread-id": "123"

We can use what is known as a thread-id, which was an iOS 10 feature. To do this, add a simple thread-id to our push, and Apple handles everything else.

Customizing Rich Notifications

Last year we could use service notifications and be able to get data and download images, which was pretty much all the flexibility that Apple gave us.

This year, we are able to create what’s known as an iOS notification content extension, which gives us the ability to do whatever we want.

{ "aps": {
    //"alert": "New Draft Pick",
    //"mutable-content": 1,
    "category": "draft-category"

The first thing you need to do is add a category. Here, I have a draft-category.

  "round": "6",
  "pick": "199",
  "first_name": "Tom",
  "last_name": "Brady",
  "position": "QB",

It contains some extra data.

CraigClayton ContentExtensionPList

We have a plist that we have to sync with it - we have to use the same ID from our push with what is in the plist. I have draft-category under UNNotificationExtensionCategory. Here, I can create as many extensions as I want and create any kind of content that I want.

You also have UNNotificationExtensionInitialContentSizeRatio. Currently, it’s set at 100%, but you can go from 1.0, to 0.1 or 0.5 - down to the size of your content.

Lastly, you have your UNNotificationExtensionDefaultContentHidden. If you keep it as NO, and Apple will display the default content. If you set it to YES, it’s all yours.

  func didReceive(_ notification: UNNotification) {

    let content = notification.request.content
    title = content.title

    update(with: content)

In the second to last file, there is a didReceive method in the notification content extension, which is where you write all of your code. Suppose you have a push that has JSON and you want to go to a feed, grab extra data and put it in here. This is everything that you need to do.

  func update(with content: UNNotificationContent) {

    if let round = content.userInfo["round"] as? String {
      lblRound.text = "R\(round)"

    if let pick = content.userInfo["pick"] as? String {
      lblPick.text = pick

    if let pos = content.userInfo["position"] as? String {
      lblPosition.text = pos

In the update method, I’m setting the round in my round label, updating my pick label, my position label, and my images.

Engaging Users Year Round

In sports, there is both an on, and offseason. There are fans who are very engaged and want to be involved in the NFL, basketball, or hockey, etc. all year long.

How do we engage these users?

CraigClayton CustomNotificationsInSeason


Instead of just regular push notifications, I can do notifications such as “Player of the Game”.

I can do “Game HUD”: instead of showing a simple score. I can do “Player of the Week (POTW)” voting. I can do custom user input such as having a whole poll that lets fans and users be engaged instead of seeing another notification that they can get rid of.

<img align="left" src="//" width="49%" vspace="20">

<img align="right" src="//" width="49%" vspace="20">


As soon as the season’s over, the NFL has an event set up every month until football season restarts.

February is the NFL Combine. In March, we have Free Agency, where all fans are engaged. In April is the NFL Draft. In May, is the Rookie Minicamp where everybody has been drafted and people want to see videos, articles, or anything that has to do with football.

In June, fans get OTAs. Videos or galleries can be sent to users within the notification without having them go into the app.

The Future of Notifications

The future of notifications includes hidden notification content, combining notifications, creating custom rich notifications, and engaging users year round.

In your app, you may not have a set on/offseason, but your users still leave and come back. Find ways to engage users in notifications, even if it’s a game.

Here are some useful links: Intro to Notifications, Advanced Notifications, and Best Practices and What’s New in User Notifications. These three will get you where you need to go.

Next Up: Learn more about fine-grained notifications in Realm

General link arrow white

About the content

This talk was delivered live in September 2017 at try! Swift NYC. The video was recorded, produced, and transcribed by Realm, and is published here with the permission of the conference organizers.

Craig Clayton

Craig Clayton is a Sr. iOS Engineer at Adept Mobile, which specializes in building mobile experiences primarily for NBA & NFL teams. Craig also volunteers as the organizer of the Suncoast iOS meetup group in the Tampa/St. Petersburg area, and prepares presentations and hands-on talks for the community. On top of all that, Craig is also the owner of Cocoa Academy – launching in Jan 2017, Cocoa Academy specializes in iOS video courses.

4 design patterns for a RESTless mobile integration »