7

I am using the UNUserNotificationCenterDelegate (> ios 10) and one of the delegate methods where I can check the response from the notification has always actionIdentifier equal "com.apple.UNNotificationDefaultActionIdentifier" no matter what I do. The "response.notification.request.content.categoryIdentifier" comes right, with the expected value, but the request.actionIdentifier never comes correctly ("mycustomactionidentifier" in the example below). Does anyone know if I'm missing something?

extension NotificationManager: UNUserNotificationCenterDelegate {


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

        completionHandler([.alert,.sound])
    }

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

        if response.notification.request.content.categoryIdentifier == "TEST" {
            if response.actionIdentifier == "mycustomactionidentifier" {
                NSLog("it finally works dude!")
            }
        }

        completionHandler()
    }
}

I added the action and category to the Notification center:

    let uploadAction = UNNotificationAction(identifier: "mycustomactionidentifier", title: "Uploaded", options: [])
    let category = UNNotificationCategory(identifier: "TEST", actions: [uploadAction], intentIdentifiers: [])
    center.setNotificationCategories([category])

and am sending the request putting the correct identifier:

    let uploadContent = UNMutableNotificationContent()
    uploadContent.title = String(number) + " asset(s) added"
    uploadContent.body = "Check your inventory to manage your assets!"
    uploadContent.categoryIdentifier = "TEST" 

    let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 6, repeats: false)

    let uploadRequestIdentifier = "mycustomactionidentifier"
    let uploadRequest = UNNotificationRequest(identifier: uploadRequestIdentifier, content: uploadContent, trigger: trigger)
    UNUserNotificationCenter.current().add(uploadRequest, withCompletionHandler: nil)
user2116499
  • 403
  • 1
  • 5
  • 15
  • when the notification comes onto your screen what does it look like? Can you add a screenshot? And which action do you click onto? – mfaani Apr 25 '17 at 19:11
  • You have a wrong comparison. Your action identifier is "mycustomactionidentifier" , but you have checked as "mycustomidentifier". Therefore the compiler simply ignored your action identifier. – Mannopson Apr 26 '17 at 01:08
  • Hi @Honey, it comes as a regular notification, with the title and body as I chose. Wherever I click in the notification it returns with the correct categoryIdentifier but with wrong actionIdentifier! – user2116499 Apr 26 '17 at 07:51
  • And @Mannopson, sorry it was a typo but in my code it is correct and still doesn't work. Thanks! – user2116499 Apr 26 '17 at 07:52

2 Answers2

11

Firstly: Register your custom actions:

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

    UNUserNotificationCenter.current().delegate = self
    UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { (granted, error) in
        if granted {
         // Access granted
        } else {
         // Access denied
        }
    }

    self.registerNotificationAction()

    return true
}

func registerNotificationAction() {

    let first = UNNotificationAction.init(identifier: "first", title: "Action", options: [])
    let category = UNNotificationCategory.init(identifier: "categoryIdentifier", actions: [first], intentIdentifiers: [], options: [])
    UNUserNotificationCenter.current().setNotificationCategories([category])
}

And create a content with a unique identifier:

func scheduleNotification() {

    // Create a content
    let content = UNMutableNotificationContent.init()
    content.title = NSString.localizedUserNotificationString(forKey: "Some title", arguments: nil)
    content.body = NSString.localizedUserNotificationString(forKey: "Body of notification", arguments: nil)
    content.sound = UNNotificationSound.default()
    content.categoryIdentifier = "categoryIdentifier"

    // Create a unique identifier for each notification
    let identifier = UUID.init().uuidString

    // Notification trigger
    let trigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 5, repeats: false)

    // Notification request
    let request = UNNotificationRequest.init(identifier: identifier, content: content, trigger: trigger)

    // Add request
    UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)

}

Lastly: Handle the notification with their default and custom actions.

   extension AppDelegate: UNUserNotificationCenterDelegate {

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

        if response.notification.request.content.categoryIdentifier == "categoryIdentifier" {

            switch response.actionIdentifier {
            case UNNotificationDefaultActionIdentifier:
                print(response.actionIdentifier)
                completionHandler()
            case "first":
                print(response.actionIdentifier)
                completionHandler()
            default:
                break;
            }
        }
    }

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

        completionHandler([.alert, .sound])
    }
}

Hope it helps!

Second Edition

Here's the results: This is going to be our UNNotificationDefaultActionIdentifier:

UNNotificationDefaultActionIdentifier

And this one is expanded version of the notification, we could handle both actions:

Expanded notification

Mannopson
  • 2,634
  • 1
  • 16
  • 32
  • Hi Mannopson, I did exactly like you said but still when I send a notification with action identifier "X, when I click the notification I get a "com.apple.UNNotificationDefaultActionIdentifier" instead of "X" in didReceive response func. Thanks for your answer. – user2116499 Apr 28 '17 at 08:02
  • @user2116499 Whenever notification is delivered to the user? And the user taps on it, the UNNotificationDefaultActionIdentifier will be called. Because it's default action and it's provided by the system. My suggestion is works perfectly. – Mannopson Apr 29 '17 at 01:09
  • Hi @Mannopson, you created an action with identifier = "first". When the you click the notification, wouldn't it be appearing the action identifier = "first"? I saw tutorials saying that this should be the behaviour. If it's not, well, then your answer is correct. Thanks! – user2116499 May 01 '17 at 07:58
  • @user2116499 This is not possible! Pull down your notification when it's appears on the top and click the Action button. – Mannopson May 01 '17 at 08:03
  • Fine! Sorry for the mess then, @Mannopson. Thank you very much for your support/help. – user2116499 May 01 '17 at 11:10
  • FWIW for the `UNNotificationDefaultActionIdentifier` callback to happen, you have to either just tap the notification or first force touch the notification (have it expand) then tap again... – mfaani Feb 20 '20 at 20:10
1

As Mannopson said, you can register a default action identifier. However I though what you need is another thing :

response.notification.request.identifier

From Apple's actionIdentifier description said This parameter may contain one the identifier of one of your UNNotificationAction objects or it may contain a system-defined identifier. which means you need to register one, hope I am right(as I am a newbie to swift)

Neldrick Yip
  • 21
  • 1
  • 3