I have come across such a scenario and I used the below code which worked for me successfully:
extension UITabBarController {
    func setTabBarVisible(visible:Bool, duration: TimeInterval = 0.20, animated:Bool) {
        if (tabBarIsVisible() == visible) { return }
        let frame = self.tabBar.frame
        let height = frame.size.height
        let offsetY = (visible ? -height : height)
        let duration = animated ? duration : 0
        var safeAreaInset:CGFloat = 0
        if #available(iOS 11, *) {
            safeAreaInset = UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0
            safeAreaInset += visible ? (UIApplication.shared.keyWindow?.safeAreaInsets.top ?? 0) : 0
        }
        if !visible, let window = self.view.window {
            if let view = window.viewWithTag(999) {
                view.removeFromSuperview()
            }
            let view = UIView()
            view.translatesAutoresizingMaskIntoConstraints = false
            window.insertSubview(view, at: 0)
            view.tag = 999
            view.leadingAnchor.constraint(equalTo: window.leadingAnchor).isActive = true
            view.trailingAnchor.constraint(equalTo: window.trailingAnchor).isActive = true
            view.bottomAnchor.constraint(equalTo: window.bottomAnchor).isActive = true
            view.heightAnchor.constraint(equalToConstant: safeAreaInset).isActive = true
            view.backgroundColor = .white
            window.sendSubview(toBack: view)
        }
        let viewFrame = CGRect(x:self.view.frame.origin.x,y:self.view.frame.origin.y,width: self.view.frame.width, height: (self.view.frame.height + offsetY - safeAreaInset))
        // animation
        UIView.animate(withDuration: duration, animations: {
            self.tabBar.frame.offsetBy(dx:0, dy:offsetY)
            self.view.frame = viewFrame
            self.view.setNeedsLayout()
            self.view.layoutIfNeeded()
        }) { (finished) in
            if finished {
                if let view = self.view.window?.viewWithTag(999) {
                    self.view.window?.sendSubview(toBack: view)
                }
            }
        }
    }
    func tabBarIsVisible() ->Bool {
        return self.tabBar.frame.origin.y < UIScreen.main.bounds.height
    }
}
You can use it like this:
Have a local variable which will store the visibility status and also update the tabbar when set:
var tabbarHidden = false {
    didSet {
        self.tabbarController.setTabBarVisible(visible: !tabbarHidden, animated: false)
        self.tabbarController.tabBar.isHidden = tabbarHidden
    }
}
Have a function to set the visibility of the tabbar:
func setTabbarVisibility() {
    if !((self.tabbarController.selectedViewController as? UINavigationController)?.topViewController?.hidesBottomBarWhenPushed ?? false) {
        let count = Globals.sharedInstance.currentEvent?.bottom.count ?? 0
        self.tabbarHidden = count == 0
    }
}
Call this function in viewWillAppear and viewDidLayoutSubviews to update it as the setting is from server.