remoteControlReceivedWithEvent works in simulator but not device

862 views Asked by At

I am working on an app that will be playing music from the iPod library. I am playing the music via MPMediaPlayerController by retrieving the selected item from a table and passing it to a detail view controller:

MPMediaItem *item = (MPMediaItem *)self.detailItem;
MPMediaItemCollection *collection = [[MPMediaItemCollection alloc] initWithItems:@[item]];
[self.musicPlayer setQueueWithItemCollection:collection];
[self.musicPlayer play];

Which starts playing the music. I have set the following values in my Info.plist to enable background use:

UIBackgroundModes
 >Item 0 - audio

And that works. When I close my app the music keeps playing. So now I am trying to get the audio controls in the control center to send messages to my app so after some reading I found that I needed to do a few things. So I created a subclass of UIResponder and added the following lines:

- (BOOL)canBecomeFirstResponder {
    return YES;
}
- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
    NSLog(@"CustomApp:remoteControlReceivedWithEvent:%@", event.description);
}

I made my AppDelegate a subclass of the custom UIResponder where I have this:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    self.window = [[MainWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    self.mainViewController = [[BrowserViewController alloc] initWithNibName:nil bundle:nil];
    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:self.mainViewController];
    self.window.rootViewController = navigationController;
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];

    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
    [self becomeFirstResponder];

    return YES;
}

and this

- (void)applicationDidEnterBackground:(UIApplication *)application {
    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
    [self becomeFirstResponder];
}

Now, my the reason why I am here is because this works in the simulator but not the device and I can't figure out why. If I launch this in the simulator and bring up the control center and start pressing the audio controls the NSLog in my custom UIResponder shows in the debugger but on the device it doesn't. What actually happens is that the play/pause button does nothing, then if I press the next or previous button it goes to the next or previous track on my iPod app and starts playing that.

It seems like there is something small missing from this equation but I cannot figure it out. I have searched the documentation as best as I can but can't find anything related to this situation and the documentation on this particular functionality seems quite limited.

3

There are 3 answers

0
Jayesh Lathiya On

Try this code in viewDidLoad() with Danilo's answer

-(void)viewDidLoad:(BOOL)animated 
{
    NSError *setCategoryErr = nil;
    NSError *activationErr  = nil;
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:0 error:&setCategoryErr];
    [[AVAudioSession sharedInstance] setActive: YES error: &activationErr];
}
3
Danilo On

in your rootViewController :

- (void)viewDidLoad:(BOOL)animated
{
    [super viewDidAppear:animated];

    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    NSError *setCategoryError = nil;
    BOOL success = [audioSession setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker error:&setCategoryError];
    if (success) {
        NSError *activationError = nil;
        success = [audioSession setActive:YES error:&activationError];
        if (!success) {
            NSLog(@"%@", activationError);
        }
    }
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
    [self becomeFirstResponder];
}

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];

    [[UIApplication sharedApplication] endReceivingRemoteControlEvents];
    [self resignFirstResponder];
}

- (BOOL)canBecomeFirstResponder
{
    return YES;
}

- (void)remoteControlReceivedWithEvent:(UIEvent *)event
{
    if (event.type == UIEventTypeRemoteControl) {
        NSLog(@"Remote control event %i subtype %i", event.type, event.subtype);

        // example for headphones
        switch (event.subtype) {
            case UIEventSubtypeRemoteControlPlay:
                break;
            case UIEventSubtypeRemoteControlPause:
                break;
            case UIEventSubtypeRemoteControlStop:
                break;
            case UIEventSubtypeRemoteControlTogglePlayPause:
                break;
            case UIEventSubtypeRemoteControlNextTrack:
                break;
            case UIEventSubtypeRemoteControlPreviousTrack:
                break;
            case UIEventSubtypeRemoteControlEndSeekingBackward:
                break;
            case UIEventSubtypeRemoteControlEndSeekingForward:
                break;

            default:
                break;
        }
    }
}
0
Franklin Kesler On

I know this answer is old but I was suffering from the same issue in iOS 10. My simulator showed the lock screen audio controls correctly, but the actual device did not. For me the fix was to make sure that when setting the category of the AVAudioSession I was NOT assigning the option: AVAudioSessionCategoryOptionMixWithOthers.

This was enough for my device to not display my lock screen audio controls. So in the end my solution is as follows:

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker|AVAudioSessionCategoryOptionAllowAirPlay|AVAudioSessionCategoryOptionAllowBluetooth|AVAudioSessionCategoryOptionAllowBluetoothA2DP error:&error];