Super_Simon
Super_Simon

Reputation: 1296

How to push a view controller from App Delegate on didReceiveRemoteNotification in Swift?

I can't find any definitive answer to this and I'm starting to struggle. The closest I have got so far is to present the desired view controller but obviously that displays it modally and not with the tab bar or nav bar.

I have in my AppDelegate the didReceiveRemoteNotification function to try and handle Firebase push notifications. Essentially I'd like to able auto-segue to a specific view controller in my app, based on the key-value pair I assign on the Firebase console.

So far, my App Delegate looks like this:

AppDelegate

    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {

        let info = userInfo as NSDictionary
        let name: String = info.value(forKey: "view-controller") as! String

    switch name {
    case "controller1":
        print("controller1")
        let storyBoard = UIStoryboard.getMainStoryboard().instantiateInitialViewController()
        UIApplication.shared.delegate!.window!!.rootViewController = storyBoard
        DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
            print("Time now reached")
            let storyboard = UIStoryboard(name: "Main", bundle: nil)
            let controller1VC = storyboard.instantiateViewController(withIdentifier: "controller1VC") as! Controller1VC
            self.window?.rootViewController?.present(controller1VC, animated: true)
        }
    default:
        print("Nothing")
    }

}

// and an extension I have...

extension UIStoryboard {
public class func getMainStoryboard() -> UIStoryboard {
    return UIStoryboard(name: "Main", bundle: nil)
}
}

So as you can see I have converted the name to a String so I can handle it then I switch it based on the result. It will instantiate the initial view controller which will always be the MainMenuVC and then after a 5 second delay (this exists purely for testing reasons) I want it to push to Controller1VC.

AppDelegate or View Controller method?

Am I on the right lines here? Or should it better to pass the result to the MainMenuVC and implement some logic to then do a performSegue which is comparatively straightforward?

As a sidebar, I am receiving and reading the data absolutely fine from Firebase, I just need to get this to start behaving!

Thank you in advance for any direction you can offer.

Upvotes: 3

Views: 3003

Answers (2)

Super_Simon
Super_Simon

Reputation: 1296

I managed to get it working as I needed with help from both Sh_Khan and the answer I found in this thread: How can I show ViewController in UITabBarController?

My initial view controller is a tabBar and therefore, this is the correct code for me:

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {

    let info = userInfo as NSDictionary
    let name: String = info.value(forKey: "view-controller") as! String

    switch name {
    case "controller1":
            let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
            let controller1VC = storyboard.instantiateViewController(withIdentifier: "controller1VC") as! Controller1VC
            let tabBar = self.window?.rootViewController as? UITabBarController
            let nav = tabBar?.selectedViewController as? UINavigationController
            nav?.pushViewController(controller1VC, animated: true)
    default:
        print("Nothing")
    }
}

So this code will essentially convert the tabBar to a UINavigationController allowing for a pushViewController to work.

I hope this helps anyone else.

Upvotes: 6

Shehata Gamal
Shehata Gamal

Reputation: 100533

In your case i recommend making the rootVC as a UINavigationController and do this

let storyboard = UIStoryboard(name: "Main", bundle: nil)

let controller1VC = storyboard.instantiateViewController(withIdentifier: "controller1VC") as! Controller1VC

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

nav.pushViewController(controller1VC, animated: true)

Upvotes: 2

Related Questions