Displaying User Notifications in the Mac OS Notification Center using Swift

Introduced for Mac OS in OS X Mountain Lion, Notification Center is an OS feature that provides an overview of alerts from applications. The behavior of notifications is controlled in the Notifications section of System Preferences. You can easily integrate your application into Notification Center by using the following Classes and Protocols:

NSUserNotification

NSUserNotificationCenter

NSUserNotificationCenterDelegate

In this article we will create a simple Swift Cocoa application that uses all three of these classes to:

  • Write a short message to a text file in the Downloads folder.
  • Display a Notification using the short message
  • Allow the user to click on the notification to open the text file.

This is a simplified application to introduce the basic mechanics of a notification. Be sure to refer to the Conclusion section below for ideas and next steps.

Step 1. Create the project in Xcode

In Xcode create a new OS X Cocoa Application, make sure that Swift is selected as the Language and that Use Storyboards is selected.

In Main.storyboard, add the following elements to the View Controller Scene > View Controller:

  • 2 Labels
  • 2 Text Fields
  • 1 Push Button

Arrange these elements on the View so it looks similar to this:

<35 image 1>

Step 2: Add Outlets and Actions to ViewController.swift

In ViewController.swift add the following Outlets and Actions:

@IBOutlet weak var nameField : NSTextField!

@IBOutlet weak var messageField : NSTextField!

@IBAction func postNotification(sender : AnyObject) {

}

Now in Main.storyboard select View Controller Scene > View Controller and press COMMAND-6 to display the Connections Inspector.

Connect the first Text Field to the nameField outlet, the second Text Field to the messageField outlet and connect the Push Button to the postNotification: action.

Step 3: Implement the postNotification: action

@IBAction func postNotification(sender : AnyObject) {  
  // Get the path to the current user's Downloads folder
  let downloadsFolder = NSHomeDirectory() + "/Downloads/"

  //Use the value of the nameField to give the output file a name
  let fileName = downloadsFolder + nameField.stringValue + ".txt"

  //Use the value of the messageField for the contents of the text file
  let contents = messageField.stringValue

  do {
    // write the contents to a text file in the downloads folder
    try contents.writeToFile(fileName, atomically: true, encoding: NSUTF8StringEncoding)

    // create a User Notification
    let notification = NSUserNotification.init()

    // set the title and the informative text
    notification.title = nameField.stringValue
    notification.informativeText = messageField.stringValue

    // put the path to the created text file in the userInfo dictionary of the notification
    notification.userInfo = ["path" : fileName]

    // use the default sound for a notification
    notification.soundName = NSUserNotificationDefaultSoundName

    // if the user chooses to display the notification as an alert, give it an action button called "View"
    notification.hasActionButton = true
    notification.actionButtonTitle = "View"

    // Deliver the notification through the User Notification Center
    NSUserNotificationCenter.defaultUserNotificationCenter().deliverNotification(notification)

  } catch {
    Swift.print(error)
  }
}

Step 4: Add the NSUserNotificationCenterDelegate protocol in AppDelegate.swift

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDelegate {

  func applicationDidFinishLaunching(aNotification: NSNotification) {
    NSUserNotificationCenter.defaultUserNotificationCenter().delegate = self
  }

  func userNotificationCenter(center: NSUserNotificationCenter, shouldPresentNotification notification: NSUserNotification) -> Bool {
    // return true to always display the User Notification

    return true

  }

  func userNotificationCenter(center: NSUserNotificationCenter, didActivateNotification notification: NSUserNotification) {

    // Get the path from the userInfo dictionary of the User Notification
    let path = notification.userInfo!["path"] as! String

    // Open the file at the path
    NSWorkspace.sharedWorkspace().openFile(path)

  }

  func applicationWillTerminate(aNotification: NSNotification) {
  }
}

In AppDelegate.swift add the NSUserNotificationCenterDelegate protocol to the class declaration. In the applicaitonDidFinishLaunching: function, set the delegate of the User Notification Center to self.

We implement two NSUserNotificationCenterDelegate functions:

userNotificationCenter:shouldPresentNotification:

This function controls whether notifications should be displayed on screen (if true) or only in Notification Center (if false).

userNotificationCenter:didActivateNotification:

This function handles the event that is fired when a user clicks on a notification or the Action button (in this case "View"). In our implementation of this function, we take the path of the text file that we created and tell the default Workspace to open the file.

Discussion

By default, the User Notifications for an application are displayed in the "Banner" style which doesn't display the Action Button for the User Notification. If you change the setting for the UserNotifications application in System Preferences > Notifications to "Alerts", the "View" and "Close" action buttons will be displayed. In addition, when "Banner" is selected the User Notification will be listed in the Notifications section of the of the Notification Center. You can also control this behavior in System Preferences.

a "Banner" style User Notification

An "Alert" style User Notification

Conclusion

User Notifications can be a great way to provide informational messages or completion notifications for background activities. An example of this is the way that Xcode displays a Build Succeeded notification if Xcode isn't the in the foreground when a build succeeds.

The above example should give you a good starting point to explore User Notifications.

You can improve your own implementation by looking into:

  • using the deliveryDate property of NSUserNotification to specify when the notification should be received
  • using the activationType, and response properties of NSUserNotification in concert with userNotificationCenter:didActivateNotification: to decide which action to take when a user responds to a notification
  • adding additional logic to userNotificationCenter:shouldPresentNotification: to determine whether to display a notification.