Difference between revisions of "An iOS 10 Local Notification Tutorial"

From Techotopia
Jump to: navigation, search
 
Line 48: Line 48:
 
   
 
   
  
[[File:]]
+
[[File:ios_11_notify_demo_request.png]]
  
 
Figure 99-1
 
Figure 99-1
Line 69: Line 69:
 
   
 
   
  
[[File:]]
+
[[File:ios_11_notify_demo_ui.png]]
  
Figure 99 2
+
Figure 99-2
  
 
== Creating the Message Content ==
 
== Creating the Message Content ==
Line 90: Line 90:
 
   
 
   
  
[[File:]]
+
[[File:ios_11_notify_demo_notification_badge.png]]
  
 
Figure 99-3
 
Figure 99-3
Line 163: Line 163:
  
  
[[File:]]
+
[[File:ios_11_notify_demo_notification.png]]
 
   
 
   
 
Figure 99-4
 
Figure 99-4
Line 257: Line 257:
  
  
[[File:]]
+
[[File:ios_11_notify_demo_actions.png]]
 
   
 
   
 
Figure 99-5
 
Figure 99-5
Line 299: Line 299:
 
   
 
   
  
[[File:]]
+
[[File:ios_11_notify_demo_global_preview_settings.png]]
  
 
Figure 99-6
 
Figure 99-6
Line 307: Line 307:
 
   
 
   
  
[[File:]]
+
[[File:ios_11_notify_demo_app_preview_settings.png]]
  
 
Figure 99-7
 
Figure 99-7
Line 331: Line 331:
  
  
[[File:]]
+
[[File:ios_11_notify_demo_hidden_content.png]]
 
   
 
   
 
Figure 99-8
 
Figure 99-8
Line 365: Line 365:
 
   
 
   
  
[[File:]]
+
[[File:ios_11_notify_demo_show_title.png]]
  
 
Figure 99-9
 
Figure 99-9

Latest revision as of 15:28, 11 April 2018


Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book


Notifications provide a mechanism for an application to schedule an alert to notify the user about an event. These notifications take the form of a notification panel containing a message accompanied by a sound and the vibration of the device.

Notifications are categorized as either local or remote. Notifications initiated by apps running on a device are referred to as local notifications. A remote notification, on the other hand, is initiated by a remote server and pushed to the device where it is displayed to the user.

Both local and remote notifications are managed using the classes of the UserNotifications framework in conjunction with the user notification center. In the course of covering the steps to create, send and manage local notifications, this chapter will also outline the various classes provided within the UserNotifications framework together with the methods provided by the user notification center.


Contents


Creating the Local Notification App Project

The first step in demonstrating the use of local notifications is to create a new Xcode project. Begin by launching Xcode and selecting the options to create a new Swift based project using the Single View Application template. When prompted to do so, name the product NotifyDemo.

Requesting Notification Authorization

Before an app can issue notifications, it must first seek permission to do so from the user. This involves making a call to the user notification center.

The user notification center is responsible for handling, managing and coordinating all of the notifications on a device. In this case, a reference to the current notification center instance needs to be obtained and the requestAuthorization method called on that object.

Edit the ViewController.swift file to import the UserNotifications framework, request authorization and add a variable to store the subtitle of the message, which the user will be able to change from within the notification later in this tutorial:

import UIKit
import UserNotifications

class ViewController: UIViewController {

    var messageSubtitle = "Staff Meeting in 20 minutes"

    override func viewDidLoad() {
        super.viewDidLoad()
        UNUserNotificationCenter.current().requestAuthorization(options: 
			[[.alert, .sound, .badge]], 
				completionHandler: { (granted, error) in
            // Handle Error
        })
    }
.
.
}

Run the app on an iOS device and tap the Allow button when the permission request dialog (Figure 99-1) appears:


Ios 11 notify demo request.png

Figure 99-1


Designing the User Interface

Select the Main.storyboard file and drag and drop a Button object so that it is positioned in the center of the scene. Using the Auto Layout Resolve Auto Layout Issues menu, select the option to reset to suggested constraints for all of the views in the view controller.

Change the text on the button to read Send Notification, display the Assistant Editor panel and establish an action connection from the button to a method named buttonPressed.

Edit the ViewController.swift file and modify the buttonPressed action method to call a method named sendNotification:

@IBAction func buttonPressed(_ sender: Any) {
    sendNotification()
}

On completion of the layout work, the user interface should match that shown in Figure 99-2 below:


Ios 11 notify demo ui.png

Figure 99-2

Creating the Message Content

The first part of the notification to be created is the message content. The content of the message for a local notification is represented by an instance of the UNMutableNotificationContent class. This class can contain a variety of options including the message title, subtitle and body text. In addition, the message may contain media content such as images and videos. Within the ViewController.swift file, add the sendNotification method as follows:

func sendNotification() {
    let content = UNMutableNotificationContent()
    content.title = "Meeting Reminder"
    content.subtitle = messageSubtitle
    content.body = "Don't forget to bring coffee."
    content.badge = 1
}

Note also that the badge property of the content object is set to 1. This configures the notification count that is to appear on the app launch icon on the device after a notification has been triggered as illustrated in Figure 99-3:


Ios 11 notify demo notification badge.png

Figure 99-3

Specifying a Notification Trigger

Once the content of the message has been created, a trigger needs to be defined that will cause the notification to be presented to the user. Local notifications can be triggered based on elapsed time interval, a specific date and time or a location change. For this example, the notification will be configured to trigger after 5 seconds have elapsed (without repeating).

func sendNotification() {
    let content = UNMutableNotificationContent()
    content.title = "Meeting Reminder"
    content.subtitle = messageSubtitle
    content.body = "Don't forget to bring coffee."
    content.badge = 1

    let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, 
			repeats: false)
}

Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book

Creating the Notification Request

The next step is to create a notification request object containing the content and trigger objects together with an identifier that can be used to access the notification later if it needs to be modified or deleted. The notification request takes the form of a UNNotificationRequest object, code for which will now need to be added to the sendNotification method:

func sendNotification() {
    let content = UNMutableNotificationContent()
    content.title = "Meeting Reminder"
    content.subtitle = messageSubtitle
    content.body = "Don't forget to bring coffee."
    content.badge = 1

    let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, 
			repeats: false)

    let requestIdentifier = "demoNotification"
    let request = UNNotificationRequest(identifier: requestIdentifier, 
			content: content, trigger: trigger)
}

Adding the Request

The request object now needs to be added to the notification center where it will be triggered when the specified time has elapsed:

func sendNotification() {
    let content = UNMutableNotificationContent()
    content.title = "Meeting Reminder"
    content.subtitle = messageSubtitle
    content.body = "Don't forget to bring coffee."
    content.badge = 1

    let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, 
			repeats: false)

    let requestIdentifier = "demoNotification"
    let request = UNNotificationRequest(identifier: requestIdentifier, 
		content: content, trigger: trigger)

    UNUserNotificationCenter.current().add(request, 
		withCompletionHandler: { (error) in
        	// Handle error
    })
}

Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book

Testing the Notification

Compile and run the NotifyDemo app on a device or simulator session. Once the app has loaded, tap the Send Notification button and press the Home button to place the app into the background. After 5 seconds have elapsed the notification will appear as shown in Figure 99 4:


Ios 11 notify demo notification.png

Figure 99-4


Open the app once again and tap the button, but do not place the app into the background. This time the notification will not appear. This is the default behavior for user notifications. If the notifications issued by an app are to appear while that app is in the foreground, an additional step is necessary.

Receiving Notifications in the Foreground

As demonstrated in the previous section, when an app that issues a notification is currently in the foreground the notification is not displayed. To change this default behavior, it will be necessary for the view controller to declare itself as conforming to the UNUserNotificationCenterDelegate protocol and implement the userNotification:willPresent method. The current class will also need to be declared as the notification delegate. Remaining within the ViewController.swift file, make these changes as follows:

import UIKit
import UserNotifications

class ViewController: UIViewController, UNUserNotificationCenterDelegate {
.
.
    override func viewDidLoad() {
        super.viewDidLoad()
        UNUserNotificationCenter.current().requestAuthorization(options: [[.alert, .sound, .badge]], completionHandler: { (granted, error) in
            // Handle Error
        })
        UNUserNotificationCenter.current().delegate = self
    }
.
.
.
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {

    completionHandler([.alert, .sound])
}

The userNotification:willPresent method simply calls the provided completion handler indicating that the notification should be presented to the user using both the alert message and sound.

Adding Notification Actions

The default action when a notification is tapped by the user is to dismiss the notification and launch the corresponding app. The UserNotifications framework also allows action buttons to be added to notifications. These buttons are displayed when the user presses down with force on the notification message, or swipes the message to the left. For this example, two action buttons will be added to the notification, one of which will instruct the app to repeat the notification while the other will allow the user to input different text to appear in the message subtitle before also repeating the notification.

This will require the creation of two notification action objects as follows:

let repeatAction = UNNotificationAction(identifier:"repeat", 
			title:"Repeat",options:[])

let changeAction = UNTextInputNotificationAction(identifier: "change", 
			title: "Change Message", options: [])

Next, these action objects need to be placed in a notification category object and the category object added to the user notification center after being assigned an identifier:

let category = UNNotificationCategory(identifier: "actionCategory", 
		actions: [repeatAction, changeAction], 
		intentIdentifiers: [], options: [])

content.categoryIdentifier = "actionCategory"

UNUserNotificationCenter.current().setNotificationCategories([category])

Combining these steps with the existing sendNotification method results in code that reads as follows:

func sendNotification() {
    let content = UNMutableNotificationContent()
    content.title = "Meeting Reminder"
    content.subtitle = messageSubtitle
    content.body = "Don't forget to bring coffee."
    content.badge = 1

    let repeatAction = UNNotificationAction(identifier:"repeat", 
		title:"Repeat",options:[])
    let changeAction = UNTextInputNotificationAction(identifier: 
		"change", title: "Change Message", options: [])

    let category = UNNotificationCategory(identifier: "actionCategory",
		 actions: [repeatAction, changeAction], 
		intentIdentifiers: [], options: [])

    content.categoryIdentifier = "actionCategory"

    UNUserNotificationCenter.current().setNotificationCategories(
							[category])
.
.
.
}

Compile and run the app on a physical device, trigger the notification and perform a deep press on the message when it appears. The action buttons should appear beneath the message as illustrated in Figure 99-5 below:


Ios 11 notify demo actions.png

Figure 99-5


Tap the Change Message button and note that the keyboard and text input field appear. Although the action buttons are now present, some work still needs to be performed to handle the actions within the view controller.

Handling Notification Actions

When an action is selected by the user, the userNotification:didReceive method of the designated notification delegate is called by the user notification center. Since the ViewController class has already been declared as implementing the UNUserNotificationCenterDelegate protocol and assigned as the delegate, all that needs to be added to the ViewController.swift file is the userNotification:didReceive method:

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive 
 response: UNNotificationResponse, withCompletionHandler completionHandler: 
  @escaping () -> Void) {

    switch response.actionIdentifier {
        case "repeat":
            self.sendNotification()
        case "change":
            let textResponse = response 
			as! UNTextInputNotificationResponse 
            messageSubtitle = textResponse.userText
            self.sendNotification()
        default:
            break
    }
    completionHandler()
}

Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book

The method is passed a UNNotificationResponse object from which we can extract the identifier of the action that triggered the call. A switch statement is then used to identify the action and take appropriate steps. If the repeat action is detected the notification is resent. In the case of the change action, the text entered by the user is obtained from the response object and assigned to the messageSubtitle variable before the notification is sent again.

Compile and run the app once again and verify that the actions perform as expected.

Hidden Notification Content

iOS provides a range of options that allow the user to control the information that is displayed within a notification when it appears on the device lock screen. As we have seen in this example, the default setting is for all of the information contained within a notification (in this case the title, subtitle and body content) to be displayed when the notification appears on the lock screen.

These notification preview settings can be specified on a per app basis, or globally for all installed apps. To view and change the current global settings, open the Settings app and select Notifications -> Show Previews. As shown in Figure 99-6, options are available to show notification previews always, only when the device is unlocked or never:


Ios 11 notify demo global preview settings.png

Figure 99-6


These global settings can be overridden for individual apps from within the Settings app by displaying the Notifications screen, selecting the app from the list and scrolling down to the Show Previews option as highlighted in Figure 99 7.


Ios 11 notify demo app preview settings.png

Figure 99-7


The current notification preview settings configured by the user may be identified by accessing the showPreviewSettings property of the current notification center settings. For example:

UNUserNotificationCenter.current().getNotificationSettings { (settings) in
    
    switch settings.showPreviewsSetting {
        case .always :
            print("Always")
        case .whenAuthenticated :
            print("When unlocked")
        case .never :
            print("Never")
    }
}

On the device on which the NotifyDemo app is installed, locate the notification preview settings for the app and change the current setting to When Unlocked. After making the change, run the app, trigger a notification and then immediately lock the device. When the notification appears it will no longer contain any information except for the app name and the word Notification (Figure 99-8):


Ios 11 notify demo hidden content.png

Figure 99-8


When creating a notification from within an app, it is possible to configure options that allow more information to be displayed in this situation. When the notification code was implemented earlier in this chapter, a UNNotificationCategory object was created and initialized with information about the notification including the identifier and the two actions. This category object was then assigned to the notification before it was sent:

.
.
let category = UNNotificationCategory(identifier: "actionCategory",
                          actions: [repeatAction, changeAction],
                intentIdentifiers: [], 
                          options: [])
        
content.categoryIdentifier = "actionCategory"
        
UNUserNotificationCenter.current().setNotificationCategories([category])
.
.

The category object also contains an array of options which, in the above code, was left empty. It is within this options array that properties can be declared that will allow the title, subtitle or both to be displayed within the lock screen notification even when the preview mode is set to When Unlocked. The two settings are represented by the .hiddenPreviewsShowSubtitle and .hiddenPreviewsShowSubtitle option values. For example, modify the code for the NotifyDemo app so the category object is initialized as follows:

let category = UNNotificationCategory(identifier: "actionCategory",
                        actions: [repeatAction, changeAction],
                        intentIdentifiers: [], 
                        options: [.hiddenPreviewsShowTitle])

Run the app, trigger a notification and lock the device. This time when the notification appears, the title is included in the preview though the subtitle and body still remain hidden:


Ios 11 notify demo show title.png

Figure 99-9


Modify the options array once more, this time adding the subtitle option as follows:

let category = UNNotificationCategory(identifier: "actionCategory",
                        actions: [repeatAction, changeAction],
                        intentIdentifiers: [], 
                        options: [.hiddenPreviewsShowTitle, 
                                  .hiddenPreviewsShowSubtitle])

This time when a notification preview from the app appears on the lock screen it will display both the title and subtitle while the body content remains hidden.

Managing Notifications

In addition to creating notifications, the UserNotifications framework also provides ways to manage notifications, both while they are still pending and after they have been delivered. One or more pending notifications may be removed by passing an array of request identifiers through to the removal method of the user notification center:

UNUserNotificationCenter.current()
 .removePendingNotificationRequests(withIdentifiers: 
			[demoIdentifer, demoIdentifier2])

Similarly, the content of a pending intent may be updated by creating an updated request object with the same identifier containing the new content and adding it to the notifications center:

UNUserNotificationCenter.current().add(updatedRequest, 
		withCompletionHandler: { (error) in
        	// Handle error
})

Finally, previously delivered notifications can be deleted from the user’s notification history by a call to the user notification center passing through one or more request identifiers matching the notifications to be deleted:

UNUserNotificationCenter.current()
 .removeDeliveredNotifications(withIdentifiers: [demoIdentifier])

Summary

Notifications can be triggered locally by an app or sent remotely via a server. Both forms of notification are managed by the UserNotifications framework. An application that needs to issue local notifications must first seek permission to do so from the user.

A notification consists of a content object, a request object and access to the notifications center. In addition, a notification may also include actions which appear in the form of buttons when a force touch press is performed on the notification message. These actions include the ability for the user to input text to be sent to the app that initiated the intent.

iOS provides users the ability to control content that is shown in the preview when the device is currently locked. The app can, however, configure options within the notification to display the title and subtitle content within the notification preview regardless of user settings.


Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book