Website Links

Wednesday, 23 December 2015

Swift - Local Notifications

There are several sorts of notifications a user can receiver in iOS, these are:
  • Lock screen notifications
  • Banner notifications
  • Alerts
Lock screen and banner notifications are quite compact and can only have 2 associated actions. Whereas alert notifications are larger and can have up to 4 actions. You can choose whether you want to receive banner notifications or alert notifications for an app by going to Settings > Notifications > [App name]. This article is aimed at teaching you how to schedule and cancel local notifications.

Notification Settings

In the App.delegate you can configure the settings for your notifications, e.g. what actions there will be and whether the action will take place in the background or visibly. Firstly, we need to be aware of what type of notifications we can have:
  • UIUserNotificationType.None: The user sees nothing when the notification is received
  • UIUserNotificationType.Badge: The user will see a number on the app icon that represents a number of unhandled notifications
  • UIUserNotificationType.Sound: The user will hear a sound when the notification is received
  • UIUserNotificationType.Alert: A banner notification, lock screen notification or alert notification will be displayed

Here is how the code for setting up a notification would look, a good place to do this is the App.delegate:

  func application(application: UIApplication, 
    didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) 
    -> Bool {
        // Override point for customization after application launch.      
        let types = UIUserNotificationType([UIUserNotificationType.Alert, 
          UIUserNotificationType.Badge])
        
        let emailAction = UIMutableUserNotificationAction()
        emailAction.destructive = false
        emailAction.authenticationRequired = false
        emailAction.activationMode = UIUserNotificationActivationMode
          .Foreground
        emailAction.identifier = "EMAIL"
        emailAction.title = "Send Email"
        
        let textAction = UIMutableUserNotificationAction()
        textAction.destructive = false
        textAction.authenticationRequired = false
        textAction.activationMode = UIUserNotificationActivationMode
          .Foreground
        textAction.identifier = "TEXT"
        textAction.title = "Send Text"
        
        let noneCategory = UIMutableUserNotificationCategory()
        noneCategory.identifier = "NONE"
        noneCategory.setActions([], forContext: 
          UIUserNotificationActionContext.Default)
        noneCategory.setActions([], forContext: 
          UIUserNotificationActionContext.Minimal)

        let emailCategory = UIMutableUserNotificationCategory()
        emailCategory.identifier = "EMAIL"
        emailCategory.setActions([emailAction], forContext:
          UIUserNotificationActionContext.Default)
        emailCategory.setActions([emailAction], forContext:
          UIUserNotificationActionContext.Minimal)

        let textCategory = UIMutableUserNotificationCategory()
        textCategory.identifier = "TEXT"
        textCategory.setActions([textAction], forContext:
          UIUserNotificationActionContext.Default)
        textCategory.setActions([textAction], forContext:
          UIUserNotificationActionContext.Minimal)

        let bothCategory = UIMutableUserNotificationCategory()
        bothCategory.identifier = "BOTH"
        bothCategory.setActions([textAction, emailAction], 
          forContext: UIUserNotificationActionContext.Default)
        bothCategory.setActions([textAction, emailAction;], 
          forContext: UIUserNotificationActionContext.Minimal)
        
        let settings :UIUserNotificationSettings = 
          UIUserNotificationSettings(forTypes: types, 
          categories: [noneCategory, emailCategory, 
                       textCategory, bothCategory])
        UIApplication.sharedApplication()
          .registerUserNotificationSettings(settings)
        
        return true
    }

The UIMutableUserNoticationCategory is something you can use when scheduling a new notification to specify what actions are available to it. The context for the actions can either be Default (up to 4) or Minimal (up to 2).

Scheduling a Notification

Scheduling a notification is incredibly simple and can be done as follows:

  let notification = UILocalNotification()

  \\ When the notification will appear
  notification.fireDate = dueDate

  \\ What the notification will say
  notification.alertBody = "Hello world"

  \\ Links what actions the notification will have with what was 
  \\ specified in the App.delegate
  notification.category = "BOTH"

  \\ Additional info that we need when the app receives a user's 
  \\ interaction with the notification
  var userInfo = [String: String]()
  userInfo["notificationId"] = bookToSave.objectID.persistentStore?
    .identifier
  notification.userInfo = userInfo
  
  UIApplication.sharedApplication()
    .scheduleLocalNotification(notification)


Cancelling a notification

Often, if a user has specified a due date for something and they edit it this you will need to cancel the existing notification and reschedule it. Finding the correct notification to cancel can sometimes be challenging and this is commonly where I rely on the userInfo I have passed to the notification:

  for notification in UIApplication.sharedApplication()
    .scheduledLocalNotifications! 
  {
    var userInfo = notification.userInfo as! [String : String]
    if (userInfo["notificationId"] == 
        bookToSave.objectID.persistentStore?.identifier) {
      UIApplication.sharedApplication()
        .cancelLocalNotification(notification)
    }
  }

It is also possible to cancel all notifications using UIApplication.sharedApplication().cancelAllLocalNotifications().

Handling actions of a notification

To handle receiving information from a notification, you will need to add the following function to your App.delegate:

  func application(application: UIApplication, 
    handleActionWithIdentifier identifier: String?, 
    forLocalNotification notification: UILocalNotification, 
    completionHandler: () -> Void)
  {
    if (identifier == "EMAIL") {
      NSNotificationCenter.defaultCenter()
        .postNotificationName("EmailPressed", object: nil)
    } else if (identifier == "TEXT") {
      NSNotificationCenter.defaultCenter()
        .postNotificationName("TextPressed", object: nil)
    }
        
    completionHandler()
  }

The method above is the first step, what it does is it gives you what action was pressed in the notification, along with the notification and a completion handler. You can then use the NSNotificationHandler to pass information to pass control to the view controller that will handle the actions. Here is an example of the notifications being handled in a view controller:

  override func viewDidLoad() {
    super.viewDidLoad()
    ...
        
    NSNotificationCenter.defaultCenter().addObserver(self, 
      selector: "sendEmail:", 
      name: "EmailPressed", 
      object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, 
      selector: "sendText:",
      name: "TextPressed",
      object: nil)
  }

  func sendEmail(notification : NSNotification) {
    ...
  }

  ...

The selector represents the method that will be called when the view controller received the event of the specified name. ':' after the method name represents that the method has a parameter.

No comments:

Post a Comment