Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle UserNotifications Actions in iOS 10

So I am able to schedule notifications like so;

//iOS 10 Notification
if #available(iOS 10.0, *) {

    var displayDate: String {
        let dateFormatter = DateFormatter()
        dateFormatter.dateStyle = DateFormatter.Style.full
        return dateFormatter.string(from: datePicker.date as Date)
    }
    let notif = UNMutableNotificationContent()


    notif.title = "I am a Reminder"
    notif.subtitle = "\(displayDate)"
    notif.body = "Here's the body of the notification"
    notif.sound = UNNotificationSound.default()
    notif.categoryIdentifier = "reminderNotification"

    let today = NSDate()
    let interval = datePicker.date.timeIntervalSince(today as Date)

    let notifTrigger = UNTimeIntervalNotificationTrigger(timeInterval: interval, repeats: false)

    let request = UNNotificationRequest(identifier: "reminderNotif", content: notif, trigger: notifTrigger)

    UNUserNotificationCenter.current().add(request, withCompletionHandler: { error in
        if error != nil {
            print(error)
           // completion(Success: false)
        } else {
            //completion(Sucess: true)
        }
        })
}

I have asked for permissions in the appDelegate and the notifications appear fine with my custom view using the notification extension.

I have added notification actions in the appDelegate for the notification category; these also appear.

//Notifications Actions 

private func configureUserNotifications() {
    if #available(iOS 10.0, *) {

        let tomorrowAction = UNNotificationAction(identifier: "tomorrowReminder", title: "Remind Me Tomorrow", options: [])

        let dismissAction = UNNotificationAction(identifier: "dismissReminder", title: "Dismiss", options: [])


        let category = UNNotificationCategory(identifier: "reminderNotification", actions: [tomorrowAction, dismissAction], intentIdentifiers: [], options: [.customDismissAction])

        UNUserNotificationCenter.current().setNotificationCategories([category])

    } else {
        // Fallback on earlier versions
    }
}

I have the same category set in the notification extension .plist file. And in the notification extension I have the following to change the text when the user taps on a action.

 //Handle Notification Actions And Update Notification Window 


 private func didReceive(_ response: UNNotificationResponse, completionHandler done: (UNNotificationContentExtensionResponseOption) -> Void) {

    if response.actionIdentifier == "tomorrowReminder" {
        print("Tomrrow Button Pressed")
        subLabel.text = "Reminder For Tomorrow"
        subLabel.textColor = UIColor.blue
        done(.dismissAndForwardAction)
    }

    if response.actionIdentifier == "dismissReminder" {
        print("Dismiss Button Pressed")
        done(.dismiss)

    } else {
        print("Else response")
        done(.dismissAndForwardAction)
    }

}

However the text does not change and none of the statements are called;

Over in the appDelegate I have the following;

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
    if #available(iOS 10.0, *) {
        UNUserNotificationCenter.current().delegate = self
        configureUserNotifications()

    }
}

extension AppDelegate: UNUserNotificationCenterDelegate {

@available(iOS 10.0, *)
private func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Void) {
    completionHandler([.alert, .sound])
}

@available(iOS 10.0, *)
private func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: () -> Void) {

    print("Recieved Action For \(response.actionIdentifier)")

    if response.actionIdentifier == "tomorrowReminder" {
        print("Tomorrow Reminder")


        //Set new reminder for tomorrow using the notification content title



        completionHandler()
    }

    if response.actionIdentifier == "dismissReminder" {
        print("Dismiss Reminder...")
        completionHandler()
    }
}

}

Neither of these functions are actually called in the appDelegate either. I am not sure if the problem with updating the extension view is related to the app delegate. I don't think so, I have followed Apple's WWDC video as well as other tutorials and look at the document API and can't figure out;

  • Why is the Notification Extension Text Labels not updating ?
  • Why are the functions in the appDelegate not getting called ?
  • How can I using the notification content in the app delegate to use for the action ?

PS: I have spent the past few weeks researching and trying to figure this out, it seemed fairly straight forward and I am unsure what I am missing. I know I am not the only one having these issues.

like image 976
A.Roe Avatar asked Sep 08 '16 15:09

A.Roe


People also ask

What is iOS APN?

Apple Push Notification service (APNs) is a cloud service that allows approved third-party apps installed on Apple devices to send push notifications from a remote server to users over a secure connection. For example, a newstand app might use APNs to send a text alert to an iPhone user about a breaking news story.

How do push notifications work on iOS?

An iOS push notification is a message that pops up on an Apple device such as an iPhone. Before receiving push notifications from an app, iOS device users must explicitly give permission. Once a user opts-in, mobile app publishers can send push notifications to the users' mobile devices.

What is silent push notification in iOS?

Silent push notifications are simply notifications that mobile app users receive without any pings, alerts, or interruptions to the user. They arrive on the mobile device and sit in the notification tray until read or dismissed.


1 Answers

I haven't checked whole code of yours, but at least, these function headers need to be changed as follows:

func userNotificationCenter(_ center: UNUserNotificationCenter,
                            willPresent notification: UNNotification,
                            withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {

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

func didReceive(_ response: UNNotificationResponse,
                completionHandler done: @escaping (UNNotificationContentExtensionResponseOption) -> Void) {

Simple rule: Remove private, add @escaping.

You may have received wrong suggestions from Xcode, but with making them private, Objective-C entry points are not generated. iOS runtime uses Objective-C selectors internally, so it cannot find your methods, thus, they are not executed.

like image 163
OOPer Avatar answered Nov 09 '22 02:11

OOPer