Search code examples
iosios10uilocalnotificationunusernotificationcenter

Local notification does not show custom action button


To test local notifications, I wrote a test app with a single view controller.
In viewDidLoad, I set up the custom action, the notification category, and the userNotificationCenter delegate.
In viewDidAppear, I set the notification content, setup a trigger that fires after 5 sec, create the notification request, and add it to the notification center.

I expect the following:

Foreground mode:
When the app is launched, it should present after 5 sec the notification in foreground. Before, the delegate function „willPresent notification“ should be called.

Background mode:
If, however, the app is put into background by pressing the home button before the trigger fires, the notification should be presented in the home screen, and the delegate function „willPresent notification“ is not called.
After the notification has been presented, the user can tap the action button.
This should bring the app into foreground, and trigger the „didReceive response“ delegate function.

What happens is:
The action button in never shown, only title and body.
When I tap the body, the delegate function „didReceive response“ is triggered using the default action identifier.

The problem:
Why is the custom action button not shown?

Here is my code:

import UIKit
import UserNotifications

class ViewController: UIViewController, UNUserNotificationCenterDelegate {

    let userNotificationCenter = UNUserNotificationCenter.current()
    let categotyId = "categoryID"
    let actionID = "actionID"

    override func viewDidLoad() {
        super.viewDidLoad()

        userNotificationCenter.requestAuthorization(options: [.alert]) { (granted, error) in
            if granted {
                let okAction = UNNotificationAction(identifier: self.actionID, 
                                                    title: "OK", 
                                                    options: [])
                let category = UNNotificationCategory(identifier: self.categotyId,
                                                              actions: [okAction],
                                                              intentIdentifiers: [], 
                                                              options: [.customDismissAction])
                self.userNotificationCenter.setNotificationCategories([category])
                self.userNotificationCenter.delegate = self
            } else {
                print("local notifications not granted")
            }
        }
        userNotificationCenter.removeAllPendingNotificationRequests()
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        let content = UNMutableNotificationContent()
        content.title = NSString.localizedUserNotificationString(forKey: "Title", arguments: nil)
        content.body = NSString.localizedUserNotificationString(forKey: "Body", arguments: nil)
        content.categoryIdentifier = categotyId

        let trigger = UNTimeIntervalNotificationTrigger(timeInterval: (5), repeats: false)
        let request = UNNotificationRequest.init(identifier: "requestID", 
                                                 content: content, 
                                                 trigger: trigger)

        userNotificationCenter.add(request, withCompletionHandler: { (error) in
            if let error = error {
                print("Could not add notification request. Error: \(error)")
            }
        })
    }

    // MARK: - Notification Delegate

    // Will be called while app is in the foreground 
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                willPresent notification: UNNotification, 
                                withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        // Show alert to the user
        print("App in foreground. Show alert.")
        completionHandler([.alert])
    }

    // Should be called after the user tapped the action button
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                didReceive response: UNNotificationResponse,
                                withCompletionHandler completionHandler: @escaping () -> Void) {
        let request = response.notification.request
        let requestID = request.identifier

        switch response.actionIdentifier {
        case actionID:
            print("Custom OK action triggered in background")
        case UNNotificationDefaultActionIdentifier:
            print("Default action triggered in background")
        default:
            print("Unknown action triggered in background, action identifier: \(response.actionIdentifier)")
        }
        UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [requestID])

        completionHandler()
    }
}

Solution

  • Sorry for my question, but maybe somebody else has the same problem:
    I simply did not know that first, only title/body is displayed:

    enter image description here

    However, I was not aware of the thin grey bar below the body. If this bar is pulled down, the custom action button appears:

    enter image description here