Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[macOS] flutter_local_notifications/FlutterLocalNotificationsPlugin.swift:87: Fatal error: Unexpectedly found nil while unwrapping an Optional value #1585

Closed
deimantasa opened this issue May 4, 2022 · 7 comments · Fixed by #1590

Comments

@deimantasa
Copy link

deimantasa commented May 4, 2022

Describe the bug
App crashes when it's in foreground and receives a push notification.

To Reproduce
Trigger push notification on macOS.

Expected behavior
App should not crash and push notification badge should be shown on the right top corner of the screen with push notification payload.

Sample code to reproduce the problem
N/A.

Additional Information
Stable and Dev versions has different crash location. However - they both do crash at the same scenario. While receiving push notification well, if app is in the background.

Version 9.5.1

flutter_local_notifications/FlutterLocalNotificationsPlugin.swift:87: Fatal error: Unexpectedly found nil while unwrapping an Optional value

Which is at

// FlutterLocalNotificationsPlugin.swift

    @available(OSX 10.14, *)
    public func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        var options: UNNotificationPresentationOptions = []
        let presentAlert = notification.request.content.userInfo[MethodCallArguments.presentAlert] as! Bool // line 87 is here
        let presentSound = notification.request.content.userInfo[MethodCallArguments.presentSound] as! Bool
        let presentBadge = notification.request.content.userInfo[MethodCallArguments.presentBadge] as! Bool
        if presentAlert {
            options.insert(.alert)
        }
        if presentSound {
            options.insert(.sound)
        }
        if presentBadge {
            options.insert(.badge)
        }
        completionHandler(options)
    }

Version 10.0.0-dev.13.

flutter_local_notifications/FlutterLocalNotificationsPlugin.swift:642: Fatal error: Unexpectedly found nil while unwrapping an Optional value

Which is at

// FlutterLocalNotificationsPlugin.swift

   @available(macOS 10.14, *)
    func extractNotificationResponseDict(response: UNNotificationResponse) -> [String: Any?] {
        var notificationResponseDict: [String: Any?] = [:]
        notificationResponseDict["notificationId"] = Int(response.notification.request.identifier)! // l642 is here
        if response.actionIdentifier == UNNotificationDefaultActionIdentifier {
            notificationResponseDict[MethodCallArguments.notificationResponseType] = 0
        } else if response.actionIdentifier != UNNotificationDismissActionIdentifier {
            notificationResponseDict[MethodCallArguments.actionId] = response.actionIdentifier
            notificationResponseDict[MethodCallArguments.notificationResponseType] = 1
        }
        notificationResponseDict["input"] = (response as? UNTextInputNotificationResponse)?.userText
        notificationResponseDict[MethodCallArguments.payload] = response.notification.request.content.userInfo[MethodCallArguments.payload]
        return notificationResponseDict
    }

Any suggestions on how to fix it and/or solve this issue are welcome!

@MaikuB
Copy link
Owner

MaikuB commented May 6, 2022

Difficult to say without a minimal app that can reproduce the issue. Also did you actually mean push notifications aka remote notifications? Wanted to confirm as I've seen others use "push notifications" when they were referring to "local notifications". If you did, what do you use to trigger and process the push notification? If it's really a push notification then I have a rough idea on the cause

@deimantasa
Copy link
Author

Apologies - it's remote push notification sent from Firebase. Our codebase at this point is very big, but I'm certain that the issue should be reproducible anywhere - will create some small project for it.

@deimantasa
Copy link
Author

deimantasa commented May 6, 2022

Update 1

I've ran flutter_local_notifications locally and within this piece

// FlutterLocalNotificationsPlugin.swift

    @available(OSX 10.14, *)
    public func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        var options: UNNotificationPresentationOptions = []
        let presentAlert = notification.request.content.userInfo[MethodCallArguments.presentAlert] as! Bool // crash happened here
        let presentSound = notification.request.content.userInfo[MethodCallArguments.presentSound] as! Bool
        let presentBadge = notification.request.content.userInfo[MethodCallArguments.presentBadge] as! Bool
        if presentAlert {
            options.insert(.alert)
        }
        if presentSound {
            options.insert(.sound)
        }
        if presentBadge {
            options.insert(.badge)
        }
        completionHandler(options)
    }

replaced all values to false - I'm no expert in Swift, therefore not sure how to fix forced unwrapping.

// FlutterLocalNotificationsPlugin.swift

 @available(OSX 10.14, *)
    public func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        var options: UNNotificationPresentationOptions = []
        let presentAlert = false
        let presentSound = false
        let presentBadge = false
        if presentAlert {
            options.insert(.alert)
        }
        if presentSound {
            options.insert(.sound)
        }
        if presentBadge {
            options.insert(.badge)
        }
        completionHandler(options)
    }

And it did the trick - macOS does not crash on receiving a remote push notification while being in the foreground.

Thus, if someone more capable in swift could fix this piece in proper unboxing, that'd fix this issue it seems.

Update 2

I'm not sure, but it seems when app is in foreground, all of the values within MethodCallArguments become nil thus unwrapping crashes.

After changing unwrapping to default to false if there is a nil

        let presentAlert = (notification.request.content.userInfo[MethodCallArguments.presentAlert] ?? false) as! Bool
        let presentSound = (notification.request.content.userInfo[MethodCallArguments.presentSound] ?? false) as! Bool
        let presentBadge = (notification.request.content.userInfo[MethodCallArguments.presentBadge] ?? false ) as! Bool

Everything works as expected.

@MaikuB
Copy link
Owner

MaikuB commented May 6, 2022

Are you able to use this branch of the plugin with your application to confirm it fixes the issue https://github.com/MaikuB/flutter_local_notifications/tree/macOSNotificationUnwrap? It's based on the latest stable release. I don't have access to a project with FCM on macOS but the fix is the same done for iOS so I'd expect it to work

@deimantasa
Copy link
Author

I was about to submit PR. Woah.

Wonderful. It does work! Thank you for prompt fix. I guess yours is much better than mine at this point deimantasa@8732716 . Can I expect this fix be included in upcoming version bump? If yes - when should it happen?

@MaikuB
Copy link
Owner

MaikuB commented May 6, 2022

Very soon. Almost identical logic exists on iOS but originally wasn't done as I didn't see push notifications being supported for Flutter macOS applications back then

@deimantasa
Copy link
Author

No problem. Thank you very much for your quick response and a fix! Have a great rest of the Friday!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants