swift 当点击推送通知时,正确地重定向到标签栏导航控制器内的视图控制器

o2gm4chl  于 2023-05-16  发布在  Swift
关注(0)|答案(5)|浏览(240)

我有一个tabBar。它的每个选项卡ViewControllers都嵌入到各自的NavigationControllers中。
层次结构:
Tabbarcontroller--> NavigationController--> VC 1--> VC 2-->... VCn(对于表1)
当我点击推送通知时,我必须重定向到其中一个视图控制器,比如VC 2。我使用的代码如下。

let navigationController = UINavigationController()
let storyboard = UIStoryboard.init(name: "Main", bundle: Bundle.main)
if let chatViewController = storyboard.instantiateViewController(withIdentifier: "chatViewController") as? ChatViewController {
    navigationController.viewControllers = [chatViewController]
    window?.rootViewController = navigationController
}

通过使用这个,我被重定向到相应的ViewController。但是,我无法回到tabBar。那么是否有可能以这样一种方式重定向,它允许我回到标签栏,从而提供与UI中相同的层次结构?
编辑:
下面的图片显示了我的布局。

我想完成以下工作:
1.当用户点击推送通知时,应用应被定向到VC-B。* 如果VC-B已经在导航堆栈的顶部,则不应为VC-B创建新对象并添加到导航堆栈。
1.如果应用程序已终止并且用户点击通知,则应打开VC-B。
为了确定应用程序是否已被终止,我设置了一个标志:

func applicationWillTerminate(_ application: UIApplication) {
    UserDefaults.standard.set(true, forKey: UserDefaultsKey.isTerminated)
}

此标志在didFinishLaunchingWithOptions函数结束时设置为false。
对于重定向,我检查此标志以确定应用程序是否已终止:

func performRedirectionToSuitableViewController(userInfo: [AnyHashable: Any]) {
  
    let isTerminated = UserDefaults.standard.object(forKey: UserDefaultsKey.isTerminated) as! Bool
    
    if isTerminated {
        
        let storyboard = UIStoryboard.init(name: "Main", bundle: Bundle.main)
        
        let tab = storyboard.instantiateViewController(withIdentifier: "tabBar") as! UITabBarController
        
        tab.selectedIndex = 0
        
        let nav = tab.viewControllers![0] as! UINavigationController
        
        let chatViewController = storyboard.instantiateViewController(withIdentifier: "chatViewController") as! ChatViewController
        
        chatViewController.chatThreadId = userInfo["thread_id"] as? String
        
        nav.pushViewController(chatViewController, animated: true)

    } else {

        if let tab = window?.rootViewController?.presentedViewController as? UITabBarController {

            let storyboard = UIStoryboard.init(name: "Main", bundle: Bundle.main)

            let chatViewController = storyboard.instantiateViewController(withIdentifier: "chatViewController") as! ChatViewController
                
            chatViewController.chatThreadId = userInfo["thread_id"] as? String
               
            if let nav = tab.selectedViewController as? UINavigationController {
                   
                nav.pushViewController(chatViewController, animated: true)
            }     
        }
    }
}

有了这段代码,我的第一个要求就部分实现了。需要确定viewcontroller是否位于导航堆栈的顶部。
并且,在终止应用的情况下,单击推送通知打开选项卡栏,其中默认选择索引被选择。
我花了几天时间试图解决这个问题。但却不能让它工作。

2g32fytz

2g32fytz1#

我想你必须做这样的事情:

let tabBar: UITabBarController // get your tab bar
tabBar.selectedIndex = 0 // eg. zero. To be sure that you are on correct tab
if let navigation = tabBar.viewControllers?[tabBar.selectedIndex] as? UINavigationController {
    let storyboard = UIStoryboard.init(name: "Main", bundle: Bundle.main)
    if let chatViewController = storyboard.instantiateViewController(withIdentifier: "chatViewController") as? ChatViewController {
        navigation.pushViewController(chatViewController, animated: true)
    }
 }
o4tp2gmn

o4tp2gmn2#

好吧,你正在设置当前的window.rootViewController,这应该是我说的TabBarViewController。这就是为什么你不能回到TabBar
你应该做的是

let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
if let chatViewController = storyboard.instantiateViewController(withIdentifier: "chatViewController") as? ChatViewController, let tabBar = storyboard.instantiateViewController(withIdentifier: "tabBar") as? UITabBarController {
    let navigationController = UINavigationController(rootViewController: chatViewController)
    navigationController.viewControllers = [chatViewController]
    tabBar.viewControllers = [navigationController]
    window?.rootViewController = tabBar
}
iovurdzv

iovurdzv3#

从选项卡栏控制器中获取当前的导航控制器。您可以使用此功能

func getVisibleViewController(_ rootViewController: UIViewController?) -> UIViewController? {
        
        var rootVC = rootViewController
        if rootVC == nil {
            rootVC = UIApplication.shared.keyWindow?.rootViewController
        }
        
        if rootVC?.presentedViewController == nil {
            return rootVC
        }
        
        if let presented = rootVC?.presentedViewController {
            if presented.isKind(of: UINavigationController.self) {
                let navigationController = presented as! UINavigationController
                return navigationController.viewControllers.last!
            }
            
            if presented.isKind(of: UITabBarController.self) {
                let tabBarController = presented as! UITabBarController
                return tabBarController.selectedViewController!
            }
            
            //UIAlertController
            if presented.isKind(of: UIAlertController.self) {
                let alertController = presented as! UIAlertController
                return alertController.presentingViewController
            }
            return getVisibleViewController(presented)
        }
        return nil
    }

使用该函数,您可以像下面这样导航视图控制器。

let mainStoryboardIpad : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
                let yourView = mainStoryboardIpad.instantiateViewController(withIdentifier: "yourView") as! NewnoteViewController

                let navi = self.getVisibleViewController(self.window!.rootViewController) as! UINavigationController
               
                navi.pushViewController(yourView, animated: true)
jdzmm42g

jdzmm42g4#

您可以在RootViewController中创建一个方法,在收到推送通知后将用户重定向到特定视图。这是我在上一个项目中所做的。

class RootViewController: UIViewController {
    private var currentView: UIViewController
    
    init() {
        self.currentView = ViewController()
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        addChildViewController(currentView)               // 1
        currentView.view.frame = view.bounds              // 2
        view.addSubview(currentView.view)                 // 3
        currentView.didMove(toParentViewController: self) // 4
    }
    
    func showDetailsScreen() {
        if let updateDetailView = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "UpdateDetailsNotif") as? UpdateDetailsViewController{
            
            let navController = UINavigationController(rootViewController: updateDetailView)

            addChildViewController(navController)
            navController.view.frame = view.bounds
            view.addSubview(navController.view)
            navController.didMove(toParentViewController: self)
            currentView.willMove(toParentViewController: nil)
            currentView.view.removeFromSuperview()
            currentView.removeFromParentViewController()
            currentView = navController
        }
        
    }
   
}

然后你可以像这样在AppDelegate上调用这个方法:

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        let application = UIApplication.shared
  
        AppDelegate.shared.rootViewController.showDetailsScreen()
       
        completionHandler()
    
    }
}
eqzww0vc

eqzww0vc5#

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

        let userInfo = response.notification.request.content.userInfo
        print("didReceive2: ", userInfo)
        Messaging.messaging().appDidReceiveMessage(userInfo)
        
            //        NotificationCenter.default.post(name: NotificationName.openRaceDAyTipsTab, object: nil)
        
        let application = UIApplication.shared
        
        if(application.applicationState == .active) {
            print("user tapped the notification bar when the app is in foreground")
        }
        
        if(application.applicationState == .inactive) {
            print("user tapped the notification bar when the app is in background")
        }
        
        guard let rootViewController = (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.window?.rootViewController else {
            return
        }
        print("got active scene")
        
        
            // handle the push notification here
        if let articleId = userInfo["articleId"] as? String {
                // use the articleId in your app logic
                // Create an instance of ArticlesDetailViewController
            let articlesDetailVC = ArticlesDetailViewController.instantiateHome()
            articlesDetailVC.articlesId = articleId
            
            if let tabBarVC = rootViewController as? UITabBarController,
               let navVC = tabBarVC.selectedViewController as? UINavigationController {
                navVC.pushViewController(articlesDetailVC, animated: true)
            }
        }
        
        completionHandler()
    }

相关问题