There are several limitations in WatchKit due to it being dependent on an iPhone device. One of these limitations is creating notifications from WatchKit because of the context of UIApplication in WatchKit. In WatchKit, UIApplication is the Apple Watch device, which does not handle notifications. The notifications architecture resides in the iPhone, not the Apple Watch. In this post, I would like to show you how to get around this and get WatchKit to schedule notifications on the iPhone.
Show Me the Code!!
First, you must register the notification actions and settings in the AppDelegate of the iPhone like you normally would:
class AppDelegate: UIResponder, UIApplicationDelegate { // AppDelegate.swift func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { // Notification actions var snoozeAction = UIMutableUserNotificationAction() snoozeAction.identifier = "snoozeAction" snoozeAction.title = "Snooze" snoozeAction.activationMode = .Background snoozeAction.destructive = false snoozeAction.authenticationRequired = false // Notification category var mainCategory = UIMutableUserNotificationCategory() mainCategory.identifier = "mainCategory" let defaultActions = [snoozeAction] let minimalActions = [snoozeAction] mainCategory.setActions(defaultActions, forContext: .Default) mainCategory.setActions(minimalActions, forContext: .Minimal) // Configure notifications let notificationSettings = UIUserNotificationSettings( forTypes: .Alert | .Badge | .Sound, categories: NSSet(objects: mainCategory) as Set<NSObject>) // Register notifications application.sharedApplication().registerUserNotificationSettings(notificationSettings) return true } }
Here’s the tricky part. Normally you would schedule the notification like below, which you would probably try in the main interface controller of the Apple Watch extension:
override func awakeWithContext(context: AnyObject?) { var notification = UILocalNotification() notification.category = "mainCategory" notification.alertTitle = "My title" notification.alertBody = "My scheduling text" notification.fireDate = NSDate(timeIntervalSinceNow: 60) notification.applicationIconBadgeNumber = 1 notification.soundName = UILocalNotificationDefaultSoundName UIApplication.sharedApplication().scheduleLocalNotification(notification) }
This is where you will discover the issue. UIApplication.sharedApplication()Â is referring to the Apple Watch. Unfortunately, Apple Watch is so dependent on the iPhone that even notifications are registered, scheduled, and triggered from the iPhone. So doing “UIApplication.sharedApplication().scheduleLocalNotification(notification)” is nonexistent on Apple Watch. You do not even get any kind of error;Â it just silently passes through without any indication of an issue.
What the Hack?
Sometimes you need to schedule a notification from the Apple Watch since some kind of interaction happened there, or your app is primarily a watch app with maybe a few configuration screens on the iPhone. To get around the limitation, you must get the Apple Watch to communicate to the iPhone to schedule the notification. Thankfully Apple added WKInterfaceController.openParentApplication to the WatchKit API at the last minute after a lot of commotion in the dev community. Here’s how to use it:
override func awakeWithContext(context: AnyObject?) { var userInfo = [ "scheduleLocalNotification": true, "category": "someCategory" "alertTitle": "My title" "alertBody": "My scheduling text" "fireDate": NSDate(timeIntervalSinceNow: 60) "applicationIconBadgeNumber": 1 "soundName": UILocalNotificationDefaultSoundName ] // Register notifications in iOS WKInterfaceController.openParentApplication(userInfo) { (replyInfo, error) -> Void in // Callback here if needed } }
This will trigger an event in the iPhone’s AppDelegate, then you can do whatever you like. You get to pass data using the “userInfo” parameter and even a nice, handy callback if needed. This is what you would do on the iPhone’s AppDelegate:
func application(application: UIApplication, handleWatchKitExtensionRequest userInfo: [NSObject : AnyObject]?, reply: (([NSObject : AnyObject]!) -> Void)!) { if let value: AnyObject = userInfo?["scheduleLocalNotification"] where value as! Bool { var notification = UILocalNotification() notification.category = userInfo?["category"] as? String notification.alertTitle = userInfo?["alertTitle"] as! String notification.alertBody = userInfo?["alertBody"] as? String notification.fireDate = userInfo?["fireDate"] as? NSDate if let badge: AnyObject = userInfo?["applicationIconBadgeNumber"] { notification.applicationIconBadgeNumber = badge as! Int } notification.soundName = userInfo?["soundName"] as? String UIApplication.sharedApplication().scheduleLocalNotification(notification) } }
This new handleWatchKitExtensionRequest function gets triggered by WatchKit on demand, as we did in the awakeWithContext of the Apple Watch. Then in the iPhone we are just reading the userInfo parameter for constructing the UILocalNotification object and finally letting the iPhone schedule it itself using it’s own UIApplication.sharedApplication() context. There you have it!
UPDATE: In watchOS 2+, use WatchConnectivity to communicate with iOS.
In watchOS 2+:
do { try WCSession.defaultSession().updateApplicationContext(userInfo) } catch { // Log error }
In iOS’s AppDelegate:
func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject]) { if let value = applicationContext["scheduleLocalNotification"] as? Bool { var notification = UILocalNotification() notification.category = applicationContext["category"] as? String notification.alertTitle = applicationContext["alertTitle"] as! String notification.alertBody = applicationContext["alertBody"] as? String notification.fireDate = applicationContext["fireDate"] as? NSDate if let badge = applicationContext["applicationIconBadgeNumber"] as? Int { notification.applicationIconBadgeNumber = badge } notification.soundName = userInfo?["soundName"] as? String UIApplication.sharedApplication().scheduleLocalNotification(notification) } }
HAPPY CODING!!
Hi How to download this code
Hello @Nani, a lot has changed since watchOS 1. See my up-to-date library extensions for UNUserNotificationCenter and Watch Connectivity.