Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

remoteControlReceivedWithEvent called on iOS 7.0 device but not iOS 8.0

I have an application that plays audio in the background. I am trying to fix a bug where the audio controls (play/pause), on the home screen (etc.), DO NOT work on iOS 8.0+ but work FINE on iOS 7.0. I have been digging through trying to figure out what the issue is and have been coming up empty. Any ideas would be greatly appreciated. Here is what I have in place.

In the Project Settings: I have ensured that UIBackgroundModes is set to audio.

In the AppDelegate.h: I have a member for the AVAudioSession* session; as well as the AVPlayer *audioPlayer;

In the AppDelegate.m:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

self.session = [AVAudioSession sharedInstance];

NSError* error = NULL;
[self.session setCategory:AVAudioSessionCategoryPlayback error:&error];
[self.session setActive:YES error:&error];

if (error) {
    NSLog(@"AVAudioSession error: %@", [error localizedDescription]);
}

In the AudioPlayerViewController.m

- (void)viewDidLoad {

//Get the Audio
NSURL *url = [NSURL URLWithString:self.audioUrl];
AVAsset *asset = [AVURLAsset URLAssetWithURL:url options:nil];

//Setup the player
self.playerItem = [AVPlayerItem playerItemWithAsset:asset];
appDelegate.audioPlayer = [AVPlayer playerWithPlayerItem:self.playerItem];

//Setup the "Now Playing"
NSMutableDictionary *mediaInfo = [[NSMutableDictionary alloc]init];
[mediaInfo setObject:self.title forKey:MPMediaItemPropertyTitle];
[mediaInfo setObject:self.artist forKey:MPMediaItemPropertyArtist];
[mediaInfo setObject:self.album forKey:MPMediaItemPropertyAlbumTitle];
[mediaInfo setObject:[NSNumber numberWithDouble:duration ] forKey:MPMediaItemPropertyPlaybackDuration];
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:mediaInfo];

}

// Process remote control events
- (void) remoteControlReceivedWithEvent:(UIEvent *)event {

NSLog(@"AudioPlayerViewController ... remoteControlReceivedWithEvent top ....subtype: %d", event.subtype);

if (event.type == UIEventTypeRemoteControl) {

    switch (event.subtype) {
        case UIEventSubtypeRemoteControlTogglePlayPause:
            [self togglePlayPause];
            break;
        case UIEventSubtypeRemoteControlPause:
            [self doPause];
            break;
        case UIEventSubtypeRemoteControlStop:
            [self doPause];
            break;
        case UIEventSubtypeRemoteControlPlay:
            [self doPlay];
            break;
        case UIEventSubtypeRemoteControlPreviousTrack:
            [self nextOrPrevTrack];
            break;
        case UIEventSubtypeRemoteControlNextTrack:
            [self nextOrPrevTrack];
            break;
        default:
            break;
    }
}

}

-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];

}

- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
[self resignFirstResponder];

}

- (BOOL) canBecomeFirstResponder {
return YES;

}

like image 367
Caleb Avatar asked Nov 18 '14 23:11

Caleb


2 Answers

Finally figured out the issue I was having. Ultimately it seemed that the events from the Remote Control on the home screen were never making it into my app and down to my view controllers. I ended up subclassing the UIWindow so that I could see what events were making their way through the chain. As UIWindow is a UIResponder I also added the - (void)remoteControlReceivedWithEvent:(UIEvent *)event to the subclass. Then in the makeKeyAndVisible I added the:

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

I started up the debugger and the -(void)makeKeyAndVisible was never called! I then searched my app delegate for the window member variable and the [window makeKeyAndVisible]; line was nowhere to be found! I added it back in (as it should have been there) and presto events are routing to the correct locations like magic. Why this was working on some versions of iOS and not others and without any other noticeable issues is beyond me.

Hope this helps someone out in the future.

like image 116
Caleb Avatar answered Sep 22 '22 12:09

Caleb


In your ViewController add

override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)

        UIApplication.sharedApplication().beginReceivingRemoteControlEvents()
        self.becomeFirstResponder()
}

override func remoteControlReceivedWithEvent(event: UIEvent) {
        // your stuff
    }

In AppDelegate add

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

var error: NSError?
        AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, error: &error)
        AVAudioSession.sharedInstance().setActive(true, error: &error)
}

SWIFT 3

UIApplication.shared.beginReceivingRemoteControlEvents()
self.becomeFirstResponder()

do {
    try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
    try AVAudioSession.sharedInstance().setActive(true)
} catch {
    print("hmmm...")
}
like image 23
Miralem Cebic Avatar answered Sep 22 '22 12:09

Miralem Cebic