Allow Menu button to exit tvOS app when pressed on presented modal view controller

2.6k Views Asked by At

I have a tvOS app, with a UITabBarController as the main entry point for the main storyboard. If the user is not logged in, the UITabBarController presents a LoginViewController modally.

When the user presses the Menu button on the Siri remote, the system automatically dismiss the LoginViewController and shows the UITabBarController. I want the app to instead exit to the tvOS headboard.

Expect the solution to involve either a UITapGestureRecognizer to override the Menu button action, or overriding pressesBegan/pressesTouched, but I haven't found a solution yet.

3

There are 3 best solutions below

0
On

I had a very similar situation, it looked like this:

               +--------------------+
        ------>| MainViewController |
               +--------------------+
                         |
           +-------------+-------------+
           |                           |
           v                           v
+---------------------+      +--------------------+
| LoginViewController |      | HomeViewController |
+---------------------+      +--------------------+

If either LoginViewController or HomeViewController are presented then I want the menu button to dismiss the app and return to the TV home screen, not to MainViewController.

After much Googling, I settled upon this solution and it seems to work well without triggering warnings or requiring a call to exit.

class MainViewController: UIViewController {
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        super.prepare(for: segue, sender: sender)
        UIApplication.shared.keyWindow?.rootViewController = segue.destination
    }
}

Hope this is helpful to somebody out there

0
On

For 2023 ...

Regarding this very old question. I'd like to point out that

exit(EXIT_SUCCESS)

solutions don't really work now.

The problem is, as you'll see, they introduce a 3-4 second delay when you quit. In simulator, it will work fine (with the 3-4 second delay) but on a device, additionally it will plain fail with erratic results.

I honestly feel the only way is to set up TV apps "naturally" - basically so that the "main screen" is indeed fundamentally you're "first / wrapper" screen, and then a back click by the user will indeed work completely naturally.

As of 2023, unless I've missed something - and that may be the case - I honestly believe that "natural" approach is the only way to handle TV apps, so that people can exit.

Unfortunately that seems to be the state of play.

5
On

This following snippet works, and is acceptable behavior based on the expected behavior for a menu button in Apples HIG for Remotes and Interactions

override func viewDidLoad() {
    super.viewDidLoad()

    let tapRecognizer = UITapGestureRecognizer(target: self, action: "tapped")
    tapRecognizer.allowedPressTypes = [NSNumber(integer: UIPressType.Menu.rawValue)];
    self.view.addGestureRecognizer(tapRecognizer)
}

func tapped() {
    exit(EXIT_SUCCESS)
}

2020s syntax: https://stackoverflow.com/a/68052750/294884