Search code examples
iosswiftpush-notificationuinavigationcontrolleruiscenedelegate

Swift : self.window?.rootViewController doesn't work in AppDelegate


I want to navigate to a certain screen when the user press on the push notification. However, self.window?.rootViewController keeps on giving me error, which is Thread 1: Swift runtime failure: force unwrapped a nil value.

Now I have tried using this solution. It did work; however, it requires me to delete the SceneDelegate.swift file along with other files, and I don't want to.

func userNotificationCenter(_ center: UNUserNotificationCenter,
                                didReceive response: UNNotificationResponse,
                                withCompletionHandler completionHandler: @escaping () -> Void) {
        print("userNotificationCenter didReceive")
        defer {
            completionHandler()
        }
        guard response.actionIdentifier == UNNotificationDefaultActionIdentifier else {
            return
        }

        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let destinationVC = storyboard.instantiateViewController(withIdentifier: "MyPage") as! PageViewController

        let navigationController = self.window?.rootViewController as! UINavigationController

        navigationController.pushViewController(destinationVC, animated: false)

        UNUserNotificationCenter.current().removeAllDeliveredNotifications()
    }

Could anyone show me an alternative way to navigate to a certain when the user presses on the push notification? Thank you in advance.


Solution

  • You should use keyWindow instead. Try this extension:

    extension UIApplication
    {
        static func getKeyWindow() -> UIWindow? {
            return shared
                .connectedScenes
                .flatMap { ($0 as? UIWindowScene)?.windows ?? [] }
                .first { $0.isKeyWindow }
        }
    }
    

    and then:

    let navigationController = UIApplication.getKeyWindow()?.rootViewController as! UINavigationController
    
    navigationController.pushViewController(destinationVC, animated: false)
    
    UNUserNotificationCenter.current().removeAllDeliveredNotifications()