-->

How to block iOS 7 control centre from controlling

2019-06-11 21:47发布

问题:

Our app explicitly blocks user form using remote-control, e.g., old springboard from pre-iOS7, earbud, by becoming the first responder to the remote-control events. However, on iOS7, the same code fails to bypass the control centre music controls.

From out tests, control centre seems to have bypassed ALL music control events including UIEventSubtypeRemoteControlPause and UIEventSubtypeRemoteControlPlay, and UIEventSubtypeRemoteControlTogglePlayPause.

Is it that control centre has its own protocol for remote control or that the way to intercept remote-control events has changed in iOS7?

The same blocking code still works perfectly with iOS6 devices. Here is what we do:

  1. Added a method in our appDelegate:

    (BOOL)canBecomeFirstResponder { return YES; }

  2. Call this in applicationDidBecomeActive:

    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];

    // Set itself as the first responder [self becomeFirstResponder];

  3. Call this in applicationWillResignActive

    // Turn off remote control event delivery [[UIApplication sharedApplication] endReceivingRemoteControlEvents];

    // Resign as first responder [self resignFirstResponder];

  4. Finally added

(void)remoteControlReceivedWithEvent:(UIEvent *)receivedEvent {

    if (receivedEvent.type == UIEventTypeRemoteControl) {

        switch (receivedEvent.subtype) {

            case UIEventSubtypeRemoteControlTogglePlayPause:
                NSLog(@"Received: UIEventSubtypeRemoteControlTogglePlayPause\n");
                break;

            case UIEventSubtypeRemoteControlPreviousTrack:
                NSLog(@"Received: UIEventSubtypeRemoteControlPreviousTrack\n");
                break;

            case UIEventSubtypeRemoteControlNextTrack:
                NSLog(@"Received: UIEventSubtypeRemoteControlNextTrack\n");
                break;

            case UIEventSubtypeRemoteControlPlay:
                NSLog(@"Received: UIEventSubtypeRemoteControlPlay\n");
                break;

            case UIEventSubtypeRemoteControlPause:
                NSLog(@"Received: UIEventSubtypeRemoteControlPause\n");
                break;

            case UIEventSubtypeRemoteControlStop:
                NSLog(@"Received: UIEventSubtypeRemoteControlStop\n");
                break;

            default:
                NSLog(@"Received: Some remove control events\n");
                break;
        }
    }
}

Any pointer will be appreciated.

回答1:

you can't block the music app. your app can become one though (apple won't like that) and then the control center would control yours



回答2:

I think I have a better idea of what happened, at least at the CoreAudio level.

When the app's audio session category is solo-ambient, the music app's play event triggers an audio session interruption similar to an alarm clock or a phone call. This will trigger app's audio session interruption listener callback with the "enter-interruption" state.

However, the music app's pause event does not trigger the listener callback with the "exit-interruption" state, as one would expect. This missing exit call effectively freezes our app's audio session. Quitting the control centre does not trigger it either. Same thing applies to a physical remote-control, except that the physical remote-control can be blocked using the firstResponder trick said in my last email. It does not work with Control Centre.

Unless I'm missing something obvious, I am more convinced that there are two bugs in either CoreAudio or other frameworks in the chain of command.

Bug 1: Audio session interruption listener's exit call cannot be made from music remote control if the entrance call is made first there.

Bug 2: Control Centre's music remote control does not conform to remote-control event mechanism.

I'm just surprised that no one ever reported this.

I think I'm going to file a bug report unless someone suggests differently.

UPDATE Bug 2 was a false alarm. After clean rebuilding everything over iOS7 SDK for a couple times, we found that the problem went away. Bug 1 still holds.