Push Notifications Tutorial for iOS: Rich Push Notifications
Learn how to modify and enhance push notifications before they are presented to the user, how to create custom UI around your push content, and more! By Mark Struzinski.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Push Notifications Tutorial for iOS: Rich Push Notifications
30 mins
- Getting Started
- Setting up New App Values
- Creating an Authentication Key
- Running the App
- Testing a Push Notification
- Modifying Push Content
- Introducing Service Extensions
- Adding a Service Extension
- Exposing Files to the Extension
- Saving Files
- Downloading an Image
- Modifying the Push Content From the Server
- Updating the Title
- Adding an Image
- Creating a Custom UI
- Adding the Target
- Configuring Info.plist
- Adding the App Group
- Building the Custom UI
- Setting up NotificationViewController
- Adding Shared Files
- Customizing the UI
- Customizing the Notification
- Implementing the Favorite Action
- Implementing the Play Action
- Where to Go From Here?
Creating a Custom UI
You can take rich notifications a step further by adding a custom UI on the top of your push content. This interface will replace the standard push notification UI by way of an app extension.
This interface is a view controller that conforms to UNNotificationContentExtension
. By implementing didReceive(_:)
, you can intercept the notification and set up your custom interface.
Adding the Target
Like before, click on File ▸ New ▸ Target…, and filter for the Notification Content Extension:
Name the content extension WendercastNotificationContent and ensure the fields are proper (using your own team and organization name):
This time, click Activate on the schema activation confirmation screen.
Configuring Info.plist
Next, you need to configure the Info.plist of the new target to display your content extension.
- In the WendercastNotificationContent group, open Info.plist.
- Expand NSExtension dictionary.
- Expand the NSExtensionAttribute dictionary.
- Update the value in UNNotificationExtensionCategory to new_podcast_available.
- Click the + to add a new key-value pair to the NSExtensionAttribute dictionary.
- Add the key UNNotificationExtensionDefaultContentHidden as a Boolean, and set the value to YES.
- Add one more Boolean key-value pair. Set the key to UNNotificationExtensionUserInteractionEnabled and the value to YES.
Your final Info.plist should look like this (the order of the keys doesn’t matter):
Here’s what these parameters are for:
UNNotificationExtensionCategory
- The value of this entry must match a value in the incoming push content. iOS needs this to determine which UI to use for displaying the notification.
- You need it because you may want to provide custom UIs for different categories of push notifications.
- If this value is missing, iOS will not invoke your extension.
UNNotificationExtensionInitialContentSizeRatio
- This value is a number between 0 and 1. It represents the aspect ratio of your custom interface.
- The default of 1 tells iOS that your initial interface height is the same as its width.
- For example, if you set this value to 0.5, then this would tell iOS that the height of your interface is half the size as its width.
- This is an estimate and allows iOS to set the initial size of your interface, preventing unnecessary resizing.
UNNotificationExtensionDefaultContentHidden
- When set to YES, the standard title, subtitle and body of the push content are not visible.
- When set to NO, the standard push content displays beneath the custom UI.
UNNotificationExtensionUserInteractionEnabled
- When set to YES, it enables user interaction with UIKit elements.
Adding the App Group
Add the same app group you created for the main app target:
- In the File navigator, click the project node.
- Select the WendercastNotificationContent target.
- Select the Signing & Capabilities tab.
- Click + Capability.
- Select App Groups.
- Select the same app group ID you created at the beginning of this tutorial.
Building the Custom UI
You probably want to focus on building the content extension logic, not waste time on tedious Interface Builder shenanigans. To give you the assist, the download content for this tutorial already contains a ready-to-be-used storyboard. Feel free to use it to replace the storyboard automatically created by Xcode.
Here’s how to do that:
- In Xcode, delete MainInterface.storyboard from the WendercastNotificationContent group. Choose Move to Trash when prompted.
- In the download materials, drag the MainInterface.storyboard file from the ContentStoryboard folder into Xcode in the WendercastNotificationContent folder.
- Check the Copy items if needed box and select the WendercastNotificationContent target in the Add to targets list.
- Click Finish.
- Open the storyboard in Xcode.
You’ll see this storyboard provides a good starting point for the notification UI. It provides UI elements for a title, podcast image, favorites button and play button. As a bonus, the auto layout constraints are already set up.
You can now focus on building the view controller.
Setting up NotificationViewController
NotificationViewController is responsible for presenting the custom notification view for your users. You’ll make the modifications necessary to present your awesome new push notification view :].
Adding Shared Files
Open the following files and add WendercastNotificationContent to their target membership in the File inspector:
- CoreDataManager.swift
- PodcastItem.swift
- Podcast.swift
- DiskCacheManager.swift
- Wendercast.xcdatamodel
You do this by checking the WendercastNotificationContent box.
This will make the data model and networking classes available to the content extension.
Customizing the UI
Look under the class declaration in NotificationViewController
. Remove this code automatically generated by Xcode:
label
viewDidLoad()
-
didReceive(_:)
‘s body
Then add the following outlets right under the class declaration:
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var favoriteButton: UIButton!
@IBOutlet weak var podcastTitleLabel: UILabel!
@IBOutlet weak var podcastBodyLabel: UILabel!
And then add a property to hold the current podcast:
var podcast: Podcast?
Lastly, add the following convenience method to load a podcast from the shared data store:
private func loadPodcast(from notification: UNNotification) {
// 1
let link = notification.request.content.userInfo["podcast-link"] as? String
// 2
guard let podcastLink = link else {
return
}
// 3
let podcast = CoreDataManager.shared.fetchPodcast(
byLinkIdentifier: podcastLink)
// 4
self.podcast = podcast
}
Here’s what you’re doing above:
- Try to get the link to the podcast from the
userInfo
object attached to the notification. The podcast link is the podcast’s unique identifier in the Core Data store. - If the link does not exist, return early.
- Use the link to fetch a Podcast model object from the Core Data store.
- Set
podcast
with a response.
Customizing the Notification
Replace the body of didReceive(_:)
with the following:
// 1
loadPodcast(from: notification)
// 2
let content = notification.request.content
podcastTitleLabel.text = content.subtitle
podcastBodyLabel.text = content.body
// 3
guard
let attachment = content.attachments.first,
attachment.url.startAccessingSecurityScopedResource()
else {
return
}
// 4
let fileURLString = attachment.url
guard
let imageData = try? Data(contentsOf: fileURLString),
let image = UIImage(data: imageData)
else {
attachment.url.stopAccessingSecurityScopedResource()
return
}
// 5
imageView.image = image
attachment.url.stopAccessingSecurityScopedResource()
Once a push notification comes in, here’s what you are doing above:
- Call the convenience method to load the podcast from the Core Data store. This sets
podcast
for use later. - Set the title and body labels to the values received from the push notification.
- Attempt to access the media attached to the service extension. If not, return early. The call to
startAccessingSecurityScopedResource()
allows you to access the attachment. - Get the URL for the attachment. Attempt to retrieve it from disk and convert the data to an image. If it fails, return early.
- If the image retrieval is successful, set the podcast image and stop accessing the resource.