techcoderx
techcoderx

Reputation: 602

UNUserNotificationCenter didReceive response not called when app is terminated

I'm working on local notifications but the problem I have is that the method didReceive Response is not being called when the app is terminated so when I tap on a notification action it just launches the app and did nothing else. But when the app is just in the background everything works as usual. Anything wrong with my code?

//MyClassNameViewController.swift

override func viewDidLoad() {
    super.viewDidLoad()

    UNUserNotificationCenter.current().delegate = self

}

func triggerAlarm1() {
    // Create an instance of notification center
    let center = UNUserNotificationCenter.current()

    // Sets the details of the notification
    let content = UNMutableNotificationContent()
    content.title = "Recorded Today's first alarm."
    content.body = "Be completely honest: how is your day so far?"
    content.sound = UNNotificationSound.default()
    content.categoryIdentifier = "notificationID1"

    // Set the notification to trigger everyday
    let triggerDaily = Calendar.current.dateComponents([.hour,.minute], from: myTimePicker1.date)
    let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDaily, repeats: true)

    // Deliver the notification
    let identifier = "UYLLocalNotification"
    let request = UNNotificationRequest(identifier: identifier,
                                        content: content, trigger: trigger)
    center.add(request, withCompletionHandler: { (error) in
        if error != nil {
            // Just in case something went wrong
            print(error!)
        }
    })

}

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

    print("didReceive Method called")

    if response.actionIdentifier == "actionOne" {
        let alertOne = UIAlertController(title: "First", message: "Some Message Here", preferredStyle: UIAlertControllerStyle.alert)
        let actionOne = UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil)
        alertOne.addAction(actionOne)
        self.present(alertOne, animated: true, completion: nil)
    }
    completionHandler()
}

//AppDelegate.swift

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.

    UNUserNotificationCenter.current().delegate = self

    // Request Authorisation
    UNUserNotificationCenter.current().requestAuthorization(options: [.alert , .sound , .badge]) { (Bool, error) in
        // insert code here
    }

    let actionOne = UNNotificationAction(identifier: "actionOne", title: "Open1", options: [.foreground])
    let catogeryOne = UNNotificationCategory(identifier: "notificationID1", actions: [actionOne], intentIdentifiers: [], options: [])
    UNUserNotificationCenter.current().setNotificationCategories([catogeryOne])

    return true
}

Upvotes: 8

Views: 8743

Answers (2)

Asad Mehmood
Asad Mehmood

Reputation: 359

I have Conformed to UNUserNotificationCenterDelegate inside AppDelegate. Everything is simple just posted my notification inside async block that will run after 0.1 second.

I am observing Notification.Name.LocalNotificationTapped inside my HomeViewController to update UI whenever this notification is observed For Example to present some popup etc

You can think about the code inside async block like you are presenting any alert or presenting any screen.

UNUserNotificationCenterDelegate

func userNotificationCenter(_ center: UNUserNotificationCenter,
                            didReceive response: UNNotificationResponse,
                            withCompletionHandler completionHandler: @escaping () -> Void) {
    
    let notificationData = response.notification.request.content.userInfo
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
        NotificationCenter.default.post(name: Notification.Name.LocalNotificationTapped, object: nil,userInfo: notificationData)
    }
    completionHandler()
}

Upvotes: 0

Mannopson
Mannopson

Reputation: 2684

Call this function inside of your action identifier and you'll be ok!

 func alertAction() {

    let alertController = UIAlertController(title: "Hello", message: "This is cool!", preferredStyle: .alert)
    alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action) in
        // Do something with handler block
    }))

    let pushedViewControllers = (self.window?.rootViewController as! UINavigationController).viewControllers
    let presentedViewController = pushedViewControllers[pushedViewControllers.count - 1]

    presentedViewController.present(alertController, animated: true, completion: nil)
}

It's super easy!

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

    print("didReceive Method called")

    if response.actionIdentifier == "actionOne" {
        DispatchQueue.main.async(execute: {
            self.alertAction()
        })
    } else if response.actionIdentifier == "actionTwo" {

    } else if response.actionIdentifier == "actionThree" {

    }
    completionHandler()
}

Fully works on Swift 3.0 and Xcode 8.0. I have changed all of the connections between the view controller. I've added a NavigationController to the initial ViewController.

Change the connections to the <code>show</code> instead of the <code>present modally</code>

AppDelegate:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.


    let center = UNUserNotificationCenter.current()
    center.delegate = self

    // Request Authorisation
    center.requestAuthorization(options: [.alert , .sound , .badge]) { (Bool, error) in
        // insert code here
    }

    let actionOne = UNNotificationAction(identifier: "actionOne", title: "Open1", options: [.foreground])
    let catogeryOne = UNNotificationCategory(identifier: "notificationID1", actions: [actionOne], intentIdentifiers: [], options: [])

    let actionTwo = UNNotificationAction(identifier: "actionTwo", title: "Open2", options: [.foreground])
    let catogeryTwo = UNNotificationCategory(identifier: "notificationID2", actions: [actionTwo], intentIdentifiers: [], options: [])

    let actionThree = UNNotificationAction(identifier: "actionThree", title: "Open3", options: [.foreground])
    let catogeryThree = UNNotificationCategory(identifier: "notificationID3", actions: [actionThree], intentIdentifiers: [], options: [])

    UNUserNotificationCenter.current().setNotificationCategories([catogeryOne, catogeryTwo, catogeryThree])

    return true
}


func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    print("willPresent method called")
    completionHandler([.alert, .sound])
}

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

    print("didReceive Method called")

    if response.actionIdentifier == "actionOne" {
        DispatchQueue.main.async(execute: {
            self.alertAction()
        })
    } else if response.actionIdentifier == "actionTwo" {

    } else if response.actionIdentifier == "actionThree" {

    }
    completionHandler()
}



func alertAction() {

    let alertController = UIAlertController(title: "Hello", message: "This is cool!", preferredStyle: .alert)
    alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action) in
        // Do something with handler block
    }))

    let pushedViewControllers = (self.window?.rootViewController as! UINavigationController).viewControllers
    let presentedViewController = pushedViewControllers[pushedViewControllers.count - 1]

    presentedViewController.present(alertController, animated: true, completion: nil)
}

Also I have deleted all of the previous suggestions from the viewDidLoad and other places.

enter image description here

Change your connections to the show and do not present as modally. If you want to show your alerts everywhere. Good luck

Upvotes: 4

Related Questions