Search code examples
iosswiftpresentviewcontrollerrootviewcontroller

Present viewController over rootViewController when a notification is tapped


When the app is in terminate state and I receive a push notification. Which if I view I want the app to load normally but it should present a viewController over the rootViewController for which I've added a close button and whenever i will tap this button i want simply dismiss this viewController.

In the method which is called when I open the app from notification I've done this:

func userNotificationCenter(_ center: UNUserNotificationCenter,
                                didReceive response: UNNotificationResponse,
                                withCompletionHandler completionHandler: @escaping () -> Void) {
    let tabBarController = self.window!.rootViewController as! UITabBarController
    self.window?.rootViewController = tabBarController
    let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
    apptVC = storyboard.instantiateViewController(withIdentifier: "NotificationVC") as! NotificationsViewController
    window?.makeKeyAndVisible()
    window?.rootViewController?.present(apptVC, animated: true, completion: nil)
completionHandler()
    }
}

But unfortunately when I do that the app crashes. I've implemented push notification using firebase. I want the app to run normally like it does it's just like presenting a view controller over the root view controller on launch when user is coming from notification.

UPDATE
here is the screenshot of my storyboard: enter image description here


Solution

  • So you'll need to insatiate tab bar controller first:

    let storyboard = UIStoryboard.init(name: "YourStoryboardName", bundle: nil)
    let tabBarController = storyboard.instantiateViewController(withIdentifier: "YourTabBarController") as! UITabBarController
    

    And insatiate all of the UINavigationControllers with the your desired view controller:

    let firstNavigationController = storyboard.instantiateViewiController(withIdentifier: "YourFirstNavigationController") as! UINavigationController
    
    let NotificationVC = storyboard.instantiateViewController(withIdentifier: "NotificationVC") as! NotificationsViewController
    

    And make them all as viewControllers of tab bar controller:

    tabBarController.viewControllers = [firstNavigationController]
    

    Which is the navigation controller should be present this view controller? For example:

    tabBarController.selectedViewController == firstNavigationController {
        firstNavigationController.present(NotificationVC, animated: true, completion: nil)
    }
    

    It's a last thing:

    self.window = UIWindow.init(frame: UIScreen.main.bounds)
    self.window?.rootViewController = tabBarController
    self.window?.makeKeyAndVisible()
    

    Note It's just recommendation and therefore I have used one UNavigationController

    So I have created a function called present().

    func present() {
    
    let storyboard = UIStoryboard.init(name: "YourStoryboardName", bundle: nil)
    let tabBarController = storyboard.instantiateViewController(withIdentifier: "YourTabBarController") as! UITabBarController
    let firstNavigationController = storyboard.instantiateViewiController(withIdentifier: "YourFirstNavigationController") as! UINavigationController
    let NotificationVC = storyboard.instantiateViewController(withIdentifier: "NotificationVC") as! NotificationsViewController
    
    tabBarController.viewControllers = [firstNavigationController]
    
    tabBarController.selectedViewController == firstNavigationController {
            firstNavigationController.present(NotificationVC, animated: true, completion: nil)
     }
    
    self.window = UIWindow.init(frame: UIScreen.main.bounds)   
    self.window?.rootViewController = tabBarController
    self.window?.makeKeyAndVisible()
    
    
        }
    }
    

    But it's not useful even I think this is useless. We'll need an action whenever notification is tapped. And we should check an action identifier like this:

    extension AppDelegate: UNUserNotificationCenterDelegate {
    
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
    
            switch response.actionIdentifier {
            case UNNotificationDefaultActionIdentifier:
                self.present()
                completionHandler()
    
            default:
                break;
            }
        }
    }
    

    Hope it helps