Hi Everybody!
Recently I’ve found out that MediaPlayer remote control event (MPRemoteCommand) handlers are not getting called in iOS application with embedded Unity player. I’m using Xcode 6.3.1 and Unity 5.0.1f1, however, it looks like it can be reproduced with any combination of currently available versions.
This is the official Apple documentation for handling remote control events on iOS: https://developer.apple.com/library/ios/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/Remote-ControlEvents/Remote-ControlEvents.html
The issue is very easy to reproduce - it’s just 24 lines of code added to an empty project.
-
Create new Single View Application in Xcode (to make working example without Unity player) or create an empty project in Unity and immediately build it targeting iOS platform (File → Build Settings…, iOS, Build) with all the settings left with their default values to get Xcode project generated by Unity (to make broken example with embedded Unity player).
-
Import MediaPlayer framework header file in AppDelegate.h (for example without Unity) or UnityAppController.h (for example with Unity):
#import <MediaPlayer/MediaPlayer.h>
- Declare a property for MPMoviePlayerController object in the class interface located in AppDelegate.h/UnityAppController.h:
@property (strong, nonatomic) MPMoviePlayerController *player;
- Insert this code which creates a player with URL (it’s a live radio station, you can use any other HTTP live audio source that you’d like to), registers handlers for play, pause and togglePlayPause remote control events and starts playing the audio (thus making application the “Now Playing” app) in the beginning of application:didFinishLaunchingWithOptions: method located in AppDelegate.m/UnityAppController.mm (you can also add it just before return statement of that method - it doesn’t matter):
self.player = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL URLWithString:@"http://81.9.96.34/eldoradio-64k"]];
[[MPRemoteCommandCenter sharedCommandCenter].playCommand addTarget:self action:@selector(playCommand)];
[[MPRemoteCommandCenter sharedCommandCenter].pauseCommand addTarget:self action:@selector(pauseCommand)];
[[MPRemoteCommandCenter sharedCommandCenter].togglePlayPauseCommand addTarget:self action:@selector(togglePlayPauseCommand)];
[self.player play];
- Add implementation of handlers to AppDelegate.m/UnityAppController.mm:
- (void)playCommand {
[self.player play];
}
- (void)pauseCommand {
[self.player pause];
}
- (void)togglePlayPauseCommand {
if (self.player.playbackState == MPMoviePlaybackStatePlaying) {
[self.player pause];
} else {
[self.player play];
}
}
-
Build and run the application. You should hear music playing once it is started.
-
Trigger some remote control events. The easiest way is to plug-in standard Apple EarPods and press play-pause button on them which should generate togglePlayPause event, but opening iOS Control Center (the UI you get by swiping the screen from the bottom) and pressing Play/Pause button from there is also okay (they should generate separate play and pause events respectively).
In the application without Unity audio stops and starts playing according to remote control events being sent.
In the application with Unity handlers are never getting called (you can set breakpoints in them and see that under debugger) and nothing happens at all. You can also notice that the appearance of iOS Control Center is completely different: in the application with embedded Unity player it has play and two rewind buttons regardless of audio state, but in the application without Unity it shows just pause button when audio is playing or just play button when it is not playing.
You can also replace MPMoviePlayerController with AVPlayer from AVFoundation framework - the result will be exactly the same.
Does anybody know any reason for this behavior and/or any workaround for it? This affects our application very badly.
Thank you for any possible suggestions/advices!
P.S.: I’ve already asked similar question before, but didn’t get any answers. The example in this one is as simple as possible.