or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

bridge-integration.mdconfiguration.mdindex.mdmethod-calls.mdnotifications.mdplugin-development.md
tile.json

notifications.mddocs/

Notification Handling

Comprehensive notification routing system for managing push notifications and local notifications with plugin integration.

Capabilities

NotificationRouter

Central notification routing system that manages push and local notifications, delegating to appropriate plugin handlers.

/**
 * Notification router that manages push and local notifications for Capacitor
 */
@objc(CAPNotificationRouter)
public class NotificationRouter: NSObject, UNUserNotificationCenterDelegate {
    
    // MARK: - Handler Properties
    
    /** Handler for push notifications */
    public weak var pushNotificationHandler: NotificationHandlerProtocol?
    
    /** Handler for local notifications */
    public weak var localNotificationHandler: NotificationHandlerProtocol?
    
    /** Whether Capacitor should automatically manage UNUserNotificationCenter delegate (computed property) */
    public var handleApplicationNotifications: Bool { get set }
    
    // MARK: - UNUserNotificationCenterDelegate Methods
    
    /**
     * Called when notification is received while app is in foreground
     * Routes to appropriate handler based on notification type
     * @param center Notification center
     * @param notification Received notification
     * @param completionHandler Completion handler for presentation options
     */
    public func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        willPresent notification: UNNotification,
        withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
    )
    
    /**
     * Called when user interacts with notification
     * Routes to appropriate handler based on notification type
     * @param center Notification center
     * @param response User's response to notification
     * @param completionHandler Completion handler
     */
    public func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        didReceive response: UNNotificationResponse,
        withCompletionHandler completionHandler: @escaping () -> Void
    )
}

Usage Examples:

// Basic notification router setup
override func instanceDescriptor() -> InstanceDescriptor {
    let descriptor = InstanceDescriptor()
    
    // Enable automatic notification handling
    descriptor.handleApplicationNotifications = true
    
    return descriptor
}

override func capacitorDidLoad() {
    super.capacitorDidLoad()
    
    // Set up notification handlers
    if let router = bridge?.notificationRouter {
        router.pushNotificationHandler = MyPushNotificationHandler()
        router.localNotificationHandler = MyLocalNotificationHandler()
    }
}

// Custom notification router setup
class CustomBridgeViewController: CAPBridgeViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Manual notification center delegate setup
        UNUserNotificationCenter.current().delegate = self
    }
}

extension CustomBridgeViewController: UNUserNotificationCenterDelegate {
    func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        willPresent notification: UNNotification,
        withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
    ) {
        // Custom handling or delegate to Capacitor router
        bridge?.notificationRouter.userNotificationCenter(
            center,
            willPresent: notification,
            withCompletionHandler: completionHandler
        )
    }
}

NotificationHandlerProtocol

Protocol that plugins must implement to handle push and local notifications.

/**
 * Protocol for handling notifications in plugins
 */
@objc(CAPNotificationHandlerProtocol) 
public protocol NotificationHandlerProtocol {
    
    /**
     * Called when notification will be presented while app is in foreground
     * @param notification The notification to be presented
     * @returns Presentation options for the notification
     */
    func willPresent(notification: UNNotification) -> UNNotificationPresentationOptions
    
    /**
     * Called when user interacts with a notification
     * @param response User's response to the notification
     */
    func didReceive(response: UNNotificationResponse)
}

Implementation Examples:

// Push notification handler
class PushNotificationHandler: NSObject, NotificationHandlerProtocol {
    
    func willPresent(notification: UNNotification) -> UNNotificationPresentationOptions {
        // Determine how to present push notifications in foreground
        let userInfo = notification.request.content.userInfo
        
        // Check if this is a silent notification
        if let aps = userInfo["aps"] as? [String: Any],
           let contentAvailable = aps["content-available"] as? Int,
           contentAvailable == 1 {
            return [] // Silent notification, don't show
        }
        
        // Show banner and play sound for regular push notifications
        return [.banner, .sound, .badge]
    }
    
    func didReceive(response: UNNotificationResponse) {
        let userInfo = response.notification.request.content.userInfo
        let actionIdentifier = response.actionIdentifier
        
        // Handle different notification actions
        switch actionIdentifier {
        case UNNotificationDefaultActionIdentifier:
            // User tapped the notification
            handleNotificationTap(userInfo: userInfo)
        case UNNotificationDismissActionIdentifier:
            // User dismissed the notification
            handleNotificationDismiss(userInfo: userInfo)
        default:
            // Custom action
            handleCustomAction(actionIdentifier, userInfo: userInfo)
        }
    }
    
    private func handleNotificationTap(userInfo: [AnyHashable: Any]) {
        // Navigate to specific screen or trigger action
        NotificationCenter.default.post(
            name: NSNotification.Name("PushNotificationTapped"),
            object: nil,
            userInfo: userInfo
        )
    }
}

// Local notification handler  
class LocalNotificationHandler: NSObject, NotificationHandlerProtocol {
    
    func willPresent(notification: UNNotification) -> UNNotificationPresentationOptions {
        // Always show local notifications with full presentation
        return [.banner, .sound, .badge]
    }
    
    func didReceive(response: UNNotificationResponse) {
        let identifier = response.notification.request.identifier
        let userInfo = response.notification.request.content.userInfo
        
        // Handle local notification response
        handleLocalNotificationResponse(
            identifier: identifier,
            userInfo: userInfo,
            actionIdentifier: response.actionIdentifier
        )
    }
    
    private func handleLocalNotificationResponse(
        identifier: String,
        userInfo: [AnyHashable: Any],
        actionIdentifier: String
    ) {
        // Process local notification interaction
        print("Local notification \(identifier) action: \(actionIdentifier)")
    }
}

Plugin Integration

How plugins integrate with the notification system for handling notifications.

// Notification-aware plugin
class NotificationPlugin: CAPPlugin, NotificationHandlerProtocol {
    
    override func load() {
        super.load()
        
        // Register as notification handler
        bridge?.notificationRouter.pushNotificationHandler = self
        bridge?.notificationRouter.localNotificationHandler = self
        
        // Request notification permissions
        requestNotificationPermissions()
    }
    
    // MARK: - Plugin Methods
    
    @objc func requestPermissions(_ call: CAPPluginCall) {
        UNUserNotificationCenter.current().requestAuthorization(
            options: [.alert, .sound, .badge]
        ) { granted, error in
            DispatchQueue.main.async {
                if let error = error {
                    call.reject("Permission request failed", "PERMISSION_ERROR", error)
                } else {
                    call.resolve(["granted": granted])
                }
            }
        }
    }
    
    @objc func scheduleLocal(_ call: CAPPluginCall) {
        let title = call.getString("title", "Notification")
        let body = call.getString("body", "")
        let delay = call.getDouble("delay", 0)
        
        let content = UNMutableNotificationContent()
        content.title = title
        content.body = body
        content.sound = .default
        
        let trigger = UNTimeIntervalNotificationTrigger(
            timeInterval: delay,
            repeats: false
        )
        
        let identifier = UUID().uuidString
        let request = UNNotificationRequest(
            identifier: identifier,
            content: content,
            trigger: trigger
        )
        
        UNUserNotificationCenter.current().add(request) { error in
            DispatchQueue.main.async {
                if let error = error {
                    call.reject("Failed to schedule notification", "SCHEDULE_ERROR", error)
                } else {
                    call.resolve(["identifier": identifier])
                }
            }
        }
    }
    
    @objc func registerForPush(_ call: CAPPluginCall) {
        DispatchQueue.main.async {
            UIApplication.shared.registerForRemoteNotifications()
            call.resolve()
        }
    }
    
    // MARK: - NotificationHandlerProtocol
    
    func willPresent(notification: UNNotification) -> UNNotificationPresentationOptions {
        let userInfo = notification.request.content.userInfo
        
        // Notify JavaScript of foreground notification
        notifyListeners("notificationReceived", data: [
            "title": notification.request.content.title,
            "body": notification.request.content.body,
            "data": userInfo
        ])
        
        // Customize presentation based on app state
        return [.banner, .sound]
    }
    
    func didReceive(response: UNNotificationResponse) {
        let notification = response.notification
        let actionIdentifier = response.actionIdentifier
        
        // Notify JavaScript of notification interaction
        notifyListeners("notificationActionPerformed", data: [
            "identifier": notification.request.identifier,
            "title": notification.request.content.title,
            "body": notification.request.content.body,
            "actionId": actionIdentifier,
            "data": notification.request.content.userInfo
        ])
    }
    
    // MARK: - Private Methods
    
    private func requestNotificationPermissions() {
        UNUserNotificationCenter.current().getNotificationSettings { settings in
            if settings.authorizationStatus == .notDetermined {
                // Will be requested by JavaScript call
            }
        }
    }
}

// Register the plugin
CAP_PLUGIN(NotificationPlugin, NotificationPlugin,
    CAP_PLUGIN_METHOD(requestPermissions, CAPPluginReturnPromise);
    CAP_PLUGIN_METHOD(scheduleLocal, CAPPluginReturnPromise);
    CAP_PLUGIN_METHOD(registerForPush, CAPPluginReturnPromise);
)

Advanced Notification Patterns

Complex notification handling scenarios and patterns.

Multi-Handler Setup:

class AdvancedNotificationManager {
    private var handlers: [NotificationHandlerProtocol] = []
    
    func addHandler(_ handler: NotificationHandlerProtocol) {
        handlers.append(handler)
    }
    
    func setupRouting(with router: NotificationRouter) {
        // Create composite handlers
        router.pushNotificationHandler = CompositePushHandler(handlers: handlers)
        router.localNotificationHandler = CompositeLocalHandler(handlers: handlers)
    }
}

class CompositePushHandler: NSObject, NotificationHandlerProtocol {
    private let handlers: [NotificationHandlerProtocol]
    
    init(handlers: [NotificationHandlerProtocol]) {
        self.handlers = handlers
    }
    
    func willPresent(notification: UNNotification) -> UNNotificationPresentationOptions {
        // Combine options from all handlers
        var options: UNNotificationPresentationOptions = []
        
        for handler in handlers {
            let handlerOptions = handler.willPresent(notification: notification)
            options.formUnion(handlerOptions)
        }
        
        return options
    }
    
    func didReceive(response: UNNotificationResponse) {
        // Notify all handlers
        for handler in handlers {
            handler.didReceive(response: response)
        }
    }
}

Conditional Notification Handling:

class ConditionalNotificationHandler: NSObject, NotificationHandlerProtocol {
    
    func willPresent(notification: UNNotification) -> UNNotificationPresentationOptions {
        let userInfo = notification.request.content.userInfo
        
        // Check notification category
        if let category = userInfo["category"] as? String {
            switch category {
            case "urgent":
                return [.banner, .sound, .badge]
            case "silent":
                return []
            case "background":
                return [.badge]
            default:
                return [.banner]
            }
        }
        
        return [.banner, .sound]
    }
    
    func didReceive(response: UNNotificationResponse) {
        let userInfo = response.notification.request.content.userInfo
        
        // Route based on notification type
        if let type = userInfo["type"] as? String {
            switch type {
            case "chat":
                handleChatNotification(response)
            case "reminder":
                handleReminderNotification(response)
            case "update":
                handleUpdateNotification(response)
            default:
                handleGenericNotification(response)
            }
        }
    }
    
    private func handleChatNotification(_ response: UNNotificationResponse) {
        // Navigate to chat screen
    }
    
    private func handleReminderNotification(_ response: UNNotificationResponse) {
        // Show reminder details
    }
    
    private func handleUpdateNotification(_ response: UNNotificationResponse) {
        // Trigger app update check
    }
    
    private func handleGenericNotification(_ response: UNNotificationResponse) {
        // Default handling
    }
}