Reputation: 910
I am trying to implement app launch (from inactive state) with an action from a local notification in iOS 10.
I have followed Launch a local notification at a specific time in iOS and the app launches fine in response to the local notification. But what I want from here is to perform an action in response to data in the notification.
In iOS 8 and 9 I had the setup in AppDelegate
func application(_ application: UIApplication, didReceive notification: UILocalNotification) {
if (application.applicationState == UIApplicationState.inactive || application.applicationState == UIApplicationState.background) {
NotificationCenter.default.post(name: Notification.Name(rawValue: "noteName", object: notification.alertBody)
and the observer catching it in ViewController
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.txtFromNotifier), name: NSNotification.Name(rawValue: "noteName", object: nil)
and in iOS 10 now in AppDelegate:
@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
// Determine the user action
switch response.actionIdentifier {
case UNNotificationDismissActionIdentifier:
print("Dismiss Action")
case UNNotificationDefaultActionIdentifier:
print("Default")
// do something here
I haven't been able to find how to get from the UNNotification Default action ("Default" gets printed in the console after launch) to passing the parameters and executing the txtFromNotifier function in ViewController. Trying to use the NotificationCenter post / addObserver combination works when the app is in the background but doesn't get there when the app is inactive.
Any ideas?
Upvotes: 3
Views: 5390
Reputation: 910
I found a solution. I wrapped a delay around the notification broadcast. My AppDelegate now looks something like this. For selecting the notification centre in didFinishLaunchingWithOptions:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if #available(iOS 10.0, *) {
let center = UNUserNotificationCenter.current()
center.delegate = self
let options: UNAuthorizationOptions = [.alert, .badge, .sound]
center.requestAuthorization(options: options) {
(granted, error) in
if !granted {
print("Something went wrong")
}
}
} else {
application.registerUserNotificationSettings(UIUserNotificationSettings(types: [.alert , .badge , .sound], categories: nil))
}
return true
}
In didReceiveNotification I select out iOS 10...
func application(_ application: UIApplication, didReceive notification: UILocalNotification) {
if #available(iOS 10.0, *) {
// different notification centre for iOS 10, see @available below
} else {
if (application.applicationState == UIApplicationState.inactive || application.applicationState == UIApplicationState.background) {
runAfterDelay(2.0) { // 2 second delay, not sure if needed but doesn't seem to hurt - runAfterDelay function is below
NotificationCenter.default.post(name: Notification.Name(rawValue: NSLocalizedString("ticker_notification_name", comment: "")), object: notification.alertBody)
}
} /*else {
// handle the local notification when the app is open, if needed
} */
}
}
and use @available option to select for iOS 10:
@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
// Determine the user action
switch response.actionIdentifier {
case UNNotificationDismissActionIdentifier:
print("Dismiss Action")
case UNNotificationDefaultActionIdentifier:
print("Default")
runAfterDelay(3.0) { // 3 second delay to give observer time to load. 3 seconds is arbitrary. runAfterDelay function is below
NotificationCenter.default.post(name: Notification.Name(rawValue: NSLocalizedString("ticker_notification_name", comment: "")), object: response) // .body
}
case "Snooze":
print("Snooze")
case "Delete":
print("Delete")
default:
print("Unknown action")
}
completionHandler()
}
and the runAfterDelay function that gives the observer time to put its socks on:
func runAfterDelay(_ delay: Double, closure:@escaping ()->()) {
let when = DispatchTime.now() + delay
DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}
I think that I did not have to make any changes with the observer - I don't see any changes in my revision history, it looks the same as the addObserver method in the original question.
Upvotes: 1