Skip to content

Local Notification Category and Action Options are exclusive instead of or'able. #2421

@agnes-ze-yerman

Description

@agnes-ze-yerman

Bug Report

Plugin(s)

@capacitor/local-notifications

Capacitor Version

💊   Capacitor Doctor  💊

Latest Dependencies:

  @capacitor/cli: 7.4.3
  @capacitor/core: 7.4.3
  @capacitor/android: 7.4.3
  @capacitor/ios: 7.4.3

Installed Dependencies:

  @capacitor/cli: 7.4.3
  @capacitor/android: 7.4.3
  @capacitor/core: 7.4.3
  @capacitor/ios: 7.4.3

[success] iOS looking great! 👌
[success] Android looking great! 👌

Platform(s)

iOS

Current Behavior

The iOS implementation of makeCategoryOptions and makeActionOptions in LocalNotifications.swift currently evaluates category option flags in an exclusive “first match wins” manner instead of combining them as intended by Apple’s UNNotificationCategoryOptions.

    /**
     * Make options for UNNotificationActions
     */
    func makeActionOptions(_ action: JSObject) -> UNNotificationActionOptions {
        let foreground = action["foreground"] as? Bool ?? false
        let destructive = action["destructive"] as? Bool ?? false
        let requiresAuthentication = action["requiresAuthentication"] as? Bool ?? false

        if foreground {
            return .foreground
        }
        if destructive {
            return .destructive
        }
        if requiresAuthentication {
            return .authenticationRequired
        }
        return UNNotificationActionOptions(rawValue: 0)
    }
    /**
     * Make options for UNNotificationCategoryActions
     */
    func makeCategoryOptions(_ type: JSObject) -> UNNotificationCategoryOptions {
        let customDismiss = type["iosCustomDismissAction"] as? Bool ?? false
        let carPlay = type["iosAllowInCarPlay"] as? Bool ?? false
        let hiddenPreviewsShowTitle = type["iosHiddenPreviewsShowTitle"] as? Bool ?? false
        let hiddenPreviewsShowSubtitle = type["iosHiddenPreviewsShowSubtitle"] as? Bool ?? false

        if customDismiss {
            return .customDismissAction
        }
        if carPlay {
            return .allowInCarPlay
        }

        if hiddenPreviewsShowTitle {
            return .hiddenPreviewsShowTitle
        }
        if hiddenPreviewsShowSubtitle {
            return .hiddenPreviewsShowSubtitle
        }

        return UNNotificationCategoryOptions(rawValue: 0)
    }

What’s wrong:

  • The function returns immediately upon encountering the first truthy flag.
  • As a result, if multiple flags are set (iosCustomDismissAction + iosAllowInCarPlay, for example), only the first one is applied.
  • UNNotificationCategoryOptions is an OptionSet intended for bitwise combination (OR’ing multiple options), but the current logic prevents that.

Impact:

  • Users cannot enable multiple options for a notification category simultaneously.
  • Features like .customDismissAction + .allowInCarPlay together are effectively impossible.
  • This behavior has existed since the method’s inception, but it only surfaces if multiple flags are needed at once.

Expected Behavior

Users should be able to set mix and match the respective options.

Code Reproduction

Other Technical Details

Additional Context

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions