UITabBarController 以编程方式添加控制器导致通知打开问题

Posted

技术标签:

【中文标题】UITabBarController 以编程方式添加控制器导致通知打开问题【英文标题】:UITabBarController programmatically added controllers causing issue on notification open 【发布时间】:2019-08-31 08:06:06 【问题描述】:

以下是我以编程方式将控制器添加到 UITabBarController 的代码

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

现在这工作正常,但是当我的应用关闭并且通知打开时,它只会将我带到主页而不是预期页面

以下是处理通知的代码

@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)

类DeeplinkHandler主方法代码

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)
        
    

现在请注意,我添加了 DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) 时间延迟来处理通知通知点击重定向到用户,只有在添加了最少这么多时间延迟的情况下,否则它不工作

如何处理这种情况并要求应用在处理通知之前等待第一个标签栏 ViewController 准备好

【问题讨论】:

我个人并不认为在application:didFinishLaunchingWithOptions: 中创建一个新的UIWindow 对象是一个好习惯。为什么不尝试写if window == nil window = UIWindow() 并且避免实例化一个新的窗口对象,即使它已经存在。这可能是您的问题的原因。 这能解决我的问题吗? 试过这个不行 不,我说是could be the reason,但我不保证就是这样。我无法弄清楚你的问题的原因是什么。这只是我更喜欢遵循的一个好习惯,因为它可以避免将来出现其他问题。 但是你使用故事板吗?如果是这样,您绝对应该从情节提要构建您的UITabBarController,并将application:didFinishLaunchingWithOptions: 用于其他非 UI 设置,并将 UI 逻辑留在情节提要和 UIViewController 类中。 【参考方案1】:

你可以复制 (tabBarController.viewControllers) 添加你的 newViewController 并设置 (tabBarController.viewControllers = newViewControllers)

【讨论】:

【参考方案2】:

您的 ViewController 未添加到 tabBarController 可能是因为您的代码在“窗口”属性可见之前执行。 为了解决这个在你的窗口初始化下方编写 makeKeyAndVisible() 函数:

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

UIApplication sharedApplication - keyWindow is nil?

要添加新的 ViewController,请获取 tabBarController 实例并附加控制器:

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

1) 如果您的应用已终止,即未在后台/前台运行,您将在 AppDelegate didFinishLaunchingWithOptions 方法的 launchOptions 中获得通知负载。当用户通过点击通知启动应用程序时执行操作:

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)如果你的应用在后台,你必须从通知UNUserNotificationCenterDelegate的didReceive方法中获取payload:

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()

【讨论】:

我想在标签栏视图控制器准备好并且不导航后推送控制器 请查看编辑后的答案,并确认它是否适合您

以上是关于UITabBarController 以编程方式添加控制器导致通知打开问题的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式制作 UITabBarController 和 UINavigationController Swift 4

UITabBarController 以编程方式添加控制器导致通知打开问题

以编程方式在 UITabBarController 和 UINavigationController 中呈现视图

从 UITabBarController 中的另一个选项卡以编程方式在 UIPageViewController 中翻页

在 indexpath.item 以编程方式呈现 UIViewController(嵌入在 UITabBarController 中)

如何以编程方式切换到 UITabBarController 中的另一个选项卡?