10

I've just had an Apple TV app rejected because of

'In addition, the Menu button on the Siri Remote does not behave as expected in your app. Specifically, when the user launches the app and taps the Menu button on the Siri Remote, the app does not exit to the Apple TV Home screen.'

I'm looking this up and from what I can tell this should be the automatic behaviour of pressing the menu button when on the initial view controller. However I have a navigation controller with a root view controller, instantiated automatically via the storyboard with no methods overridden and nothing happens when I press the menu button on this view controller.

Can someone tell me if I'm missing something or if there's a way of implementing this manually?

I'm thinking I could just intercept the menu button press and call exit(0), but that doesn't seem like a graceful way of exiting.

Mark Bridges
  • 8,228
  • 4
  • 50
  • 65
  • If you're seeing this behavior in, say, an empty app with just the storyboard setup you describe, you may have found a bug. (If not, start working piecewise to see how your app differs.) [File that bug](http://bugreport.apple.com). – rickster Oct 24 '15 at 16:33
  • Yeah I'm pretty sure it's a bug. I'm going to file a bug report. If I create a brand new view controller, with nothing on it, it works. If I add a few labels, buttons, image views and custom fonts (even without hooking anything up or using my own subclasses) it suddenly stops. – Mark Bridges Oct 24 '15 at 16:37
  • Example of how to return to the Apple TV home screen manually in Swift: [Allow Siri Remote Menu button when Play/Pause button is overridden](http://stackoverflow.com/a/38685417/2108547). – Daniel Storm Jul 31 '16 at 18:19

6 Answers6

5

I just had an app rejected for this reason too. In my case the problem was overriding the press<Phase>d:withEvent group of methods without calling the super implementation.

So I changed this:

-(void)pressesBegan:(NSSet*)presses withEvent:(UIPressesEvent *)event {
    // my code
}

To this:

-(BOOL)ignoreMenu:(NSSet*)presses {
    return ((UIPress *)[presses anyObject]).type == UIPressTypeMenu;
}

-(void)pressesBegan:(NSSet*)presses withEvent:(UIPressesEvent *)event {
    if ([self ignoreMenu:presses]) return [super pressesBegan:presses withEvent:event];
    // my code
}

And the menu button works again. What's confusing is that the Home button continues to work whether you call the super or not.

Shaun Inman
  • 1,968
  • 1
  • 19
  • 28
2

My complete working code as of tvOS 9.1 (compiled under Objective-C++)

bool AppRespondedToBack = false;
-(void)pressesBegan:(NSSet*)presses withEvent:(UIPressesEvent *)event
{
    UIPress *UP = (UIPress *)presses.anyObject;
    if ( UP && UP.type == UIPressTypeMenu )
    {
        //OnBack should be where you handle the back operation in your app
        AppRespondedToBack = OnBack();
        if ( !AppRespondedToBack )
            // Let AppleTV return to the home screen
            [super pressesBegan:presses withEvent:event];
    }
    else
        [super pressesBegan:presses withEvent:event];
}
-(void)pressesEnded:(NSSet*)presses withEvent:(UIPressesEvent *)event
{
    UIPress *UP = (UIPress *)presses.anyObject;
    if ( UP && UP.type == UIPressTypeMenu )
    {
        if ( !AppRespondedToBack )
             // Let AppleTV return to the home screen
            [super pressesEnded:presses withEvent:event];
    }
    else
        [super pressesEnded:presses withEvent:event];
}
RelativeGames
  • 1,593
  • 2
  • 18
  • 27
  • BTW, controllerUserInteractionEnabled also needs to be set to YES (for Objective C) or true (for Swift), at the ViewController level, else passing the presses events to super, for the menu key has no effect. – Gino Feb 27 '17 at 17:43
1

In a more generic way, the Menu button should take you to the home screen only in some conditions, first one would be when you start the app and click the Menu button, and later on in your app if you are at the 'root view' of your app.

If you display something on the screen, like a popover/dialog which is not controlled by the standard sdk but manualyl by yourself (ie adding a UIView as popover), then the Menu button should just act as a 'cancel/go back' like it would do on the navigation controller.

-(void)pressesBegan/Ended:(NSSet*)presses withEvent:(UIPressesEvent *)event {
    if( presses.anyObject.type == UIPressTypeMenu) {
        if ( !somePopoverDisplayed) {
                // Let the sdk do its thing with the menu button 
            [super pressesBegan:presses withEvent:event];
        } else {
            // otherwise handle the menu button yourself ...
        }
        return;
    }

    // handle other buttons
}
Bluedays
  • 151
  • 5
  • This is the one that worked for me, with a minor difference. For whatever reason, calling the [super pressesBegan...] method made it so the app *didn't* return to the apple tv menu – erparker Nov 08 '15 at 20:47
1

Here is the snipped of code that ended up working for me:

-(void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event {
    if( presses.anyObject.type == UIPressTypeMenu) {
        if (scene.view.paused == YES) {
            // This will return to the Apple TV Menu           
        } else {
            // This allows your code to run without exiting the app
            [self pauseScene];
            [super pressesBegan:presses withEvent:event];
        }
        return;
    }
}
erparker
  • 1,301
  • 10
  • 21
0

So I ended up begrudgingly calling exit(0) like so

- (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
{
    [super pressesBegan:presses withEvent:event];

    if (presses.anyObject.type == UIPressTypeMenu)
    {
        exit(0);
    }
}

It's not quite as neat as when it works automatically; you end up with a blurry white view for about half a second instead of the more graceful fade out animation. It does however work and I can confirm that I made it through Apple's review process doing it this way.

Mark Bridges
  • 8,228
  • 4
  • 50
  • 65
  • 2
    Then you were lucky. Last time I made an `exit()` call, it was rejected. Apple said you mustn't call exit in apps. – Mecki Nov 30 '15 at 18:17
0

What sorted it out for me was just removing the gesture recogniser from your view (for your Menu button) when you don't need it anymore.

Then when, you have a situation where you want the Menu button to for example, go back to a previous screen, then just add your gesture recogniser again.

That way the Menu button works the way it should, without you having to call exit() or force your app to quit some other way.

DJDLTD
  • 1