3

Following is my code to add controllers to UITabBarController programmatically

class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

var firstTabNavigationController : UINavigationController!
var secondTabNavigationControoller : UINavigationController!
var thirdTabNavigationController : UINavigationController!
var fourthTabNavigationControoller : UINavigationController!
var fifthTabNavigationController : UINavigationController!


func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.
    Fabric.with([Crashlytics.self])

   window = UIWindow(frame: UIScreen.main.bounds)


    window?.backgroundColor = UIColor.black


    let tabBarController = UITabBarController()

    firstTabNavigationController = UINavigationController.init(rootViewController: FirstViewController())
    secondTabNavigationControoller = UINavigationController.init(rootViewController: SecondViewController())
    thirdTabNavigationController = UINavigationController.init(rootViewController: ThirdViewController())
    fourthTabNavigationControoller = UINavigationController.init(rootViewController: FourthViewController())
    fifthTabNavigationController = UINavigationController.init(rootViewController: FifthViewController())

    tabBarController.viewControllers = [firstTabNavigationController, secondTabNavigationControoller, thirdTabNavigationController, fourthTabNavigationControoller, fifthTabNavigationController]


    let item1 = UITabBarItem(title: "Home", image: UIImage(named: "ico-home"), tag: 0)
    let item2 = UITabBarItem(title: "Contest", image:  UIImage(named: "ico-contest"), tag: 1)
    let item3 = UITabBarItem(title: "Post a Picture", image:  UIImage(named: "ico-photo"), tag: 2)
    let item4 = UITabBarItem(title: "Prizes", image:  UIImage(named: "ico-prizes"), tag: 3)
    let item5 = UITabBarItem(title: "Profile", image:  UIImage(named: "ico-profile"), tag: 4)

    firstTabNavigationController.tabBarItem = item1
    secondTabNavigationControoller.tabBarItem = item2
    thirdTabNavigationController.tabBarItem = item3
    fourthTabNavigationControoller.tabBarItem = item4
    fifthTabNavigationController.tabBarItem = item5

    UITabBar.appearance().tintColor = UIColor(red: 0/255.0, green: 146/255.0, blue: 248/255.0, alpha: 1.0)

    self.window?.rootViewController = tabBarController

    window?.makeKeyAndVisible()

    return true
}

Now this works fine but when my app is closed and notification is open it just takes me to homepage rather than expected page

Following is code to handle notification

@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
    // Called to let your app know which action was selected by the user for a given notification.
    let userInfo = response.notification.request.content.userInfo as? NSDictionary
    var userNotification : UserNotification?
    if userInfo is [String : Any] {
        userNotification = createNSaveNotification(userInfo as! [AnyHashable : Any])
    }
    DeeplinkHandler.handleNotification(userNotification: userNotification)
}

class DeeplinkHandler main method code

class func handleNotification(userNotification :  UserNotification?){
    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) {
        if let tabBarController = appDelegate.window?.rootViewController as? UITabBarController,
            let navController = tabBarController.selectedViewController as? UINavigationController {
            handleDeeplinkByType(navController,userNotification)
        }
    }
}

Now observe I have added DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) time delay to handle notification notification click redirects to user only if minimum this much time delay is added otherwise it is not working

How to handle this situation and ask app to wait for first tab bar ViewController to get ready before handling notification

Cœur
  • 37,241
  • 25
  • 195
  • 267
amodkanthe
  • 4,345
  • 6
  • 36
  • 77
  • 1
    I personally don't believe that creating a new `UIWindow` object is a good practice in `application:didFinishLaunchingWithOptions:`. Why not try to write `if window == nil {window = UIWindow()}` and you avoid instantiating a new window object even if it already exists. This could be the reason of your problem. – Vlad Rusu Aug 31 '19 at 08:57
  • will that solve my issue? – amodkanthe Aug 31 '19 at 09:00
  • tried this not working – amodkanthe Aug 31 '19 at 09:03
  • No, I said that it `could be the reason`, but I don't guarantee that this is it. I can't figure out what's the reason for your issue. This was just a good practice which I prefer to follow because it can avoid other issues in the future. – Vlad Rusu Aug 31 '19 at 09:25
  • But do you use a storyboard? If so, you should definitely build your `UITabBarController` from the storyboard and use `application:didFinishLaunchingWithOptions:` for other non-UI setup and leave the UI logic into storyboards and `UIViewController` classes. – Vlad Rusu Aug 31 '19 at 09:28

2 Answers2

0

You can copy (tabBarController.viewControllers) add your newViewController and set (tabBarController.viewControllers = newViewControllers)

0

Your ViewController is not being added to tabBarController may be because your code is executed before the 'window' property is visible. For resolving this write makeKeyAndVisible() function just below your window initialisation:

window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()

UIApplication sharedApplication - keyWindow is nil?

For adding a new ViewController, get the tabBarController instance and append the controller :

    tabBarController.viewControllers = [firstTabNavigationController, secondTabNavigationController]
    tabBarController.viewControllers?.append(thirdTabNavigationController)

1) If your app is terminated i.e. not running in background/foreground, you will get the notification payload in launchOptions in AppDelegate didFinishLaunchingWithOptions method. Perform action when user launches the app from tapping on notification:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

    if let launchOpt =  launchOptions?[UIApplication.LaunchOptionsKey.remoteNotification] as? [AnyHashable: Any] {
        let payload = launchOpt["aps"]
        // your code to go to specific page.
        (window?.rootViewController as? UITabBarController)?.selectedIndex = 3
    }
    return true
}

2) If your app is in background, you have to get the payload from notification UNUserNotificationCenterDelegate's didReceive method:

func userNotificationCenter(
_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void) {

let userInfo = response.notification.request.content.userInfo

if let payload = userInfo["aps"] as? [String: AnyObject] {

  // your code to go to specific page.
  (window?.rootViewController as? UITabBarController)?.selectedIndex = 2

  }
}
completionHandler()
}
Amyth
  • 383
  • 3
  • 9