今天要说的代码在这里【Light & Shadow】(https://github.com/RonbeKing/Light-Shallow/blob/master/Light%20%26%20Shallow/Light%20%26%20Shallow/VideoView/LSVideoPlayerView.m)
我们要实现的功能是在APP进入后台后,仍然可以进行音视频的播放,并且在锁屏情况下进行播放控制。
1、后台播放
类似QQ音乐的后台音频播放比较简单,因为只有音频,没有视频,可以使用AVAudioPlayer
,只需要对AVAudioSession进行一下设置
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
[audioSession setActive:YES error:nil];
然后开启background mode中音频播放就可以了,如下图:到这里就可以锁屏播放音频了。
再复杂一点的情况是,使用AVPlayer
进行视频播放时,也希望可以后台播放音频,类似虎牙APP在看直播的时候,APP进入后台,虽然画面看不到了,但依然可以听到直播的声音。这需要额外做两件事,在APP进入后台时,将AVPlayerLayer移除;在APP进入前台时,再次添加AVPlayerLayer。如下:
到这里实现了后台的音频播放。下面介绍锁屏控制。
2、锁屏控制
锁屏控制分两部分来讲,一是锁屏界面显示,二是锁屏界面控制。
1)锁屏界面显示
设置锁屏界面信息显示,直接看代码就好,就是设置各个参数:
- (void)updateRemoteInfoCenter{
if (!self.player) {
return;
}
MPNowPlayingInfoCenter* infoCenter = [MPNowPlayingInfoCenter defaultCenter];
NSMutableDictionary* info = [NSMutableDictionary dictionary];
// 歌曲名
[info setObject:@"歌曲名称" forKey:MPMediaItemPropertyTitle];
[info setObject:@"专辑名称" forKey:MPMediaItemPropertyAlbumTitle];
// 封面图片
MPMediaItemArtwork *artwork = [[MPMediaItemArtwork alloc] initWithBoundsSize:CGSizeMake(250, 250) requestHandler:^UIImage * _Nonnull(CGSize size) {
UIImage* image = [UIImage imageNamed:@"cover3.jpg"];
return image;
}];
[info setObject:artwork forKey:MPMediaItemPropertyArtwork];
// 设置进度
NSNumber* duration = @(CMTimeGetSeconds(self.player.currentItem.duration));
NSNumber* currentTime = @(CMTimeGetSeconds(self.player.currentItem.currentTime));
if (!duration || !currentTime) {
return;
}
[info setObject:duration forKey:MPMediaItemPropertyPlaybackDuration];
[info setObject:currentTime forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime];
[info setObject:@(self.player.rate) forKey:MPNowPlayingInfoPropertyPlaybackRate];
infoCenter.nowPlayingInfo = info;
}
2)添加播放控制
锁屏界面除了歌曲item的曲目信息,还有播放、暂停、进度控制等,我们需要通过MPRemoteCommandCenter
来创建MPRemoteCommand
实例,如下:
#pragma mark -- MPRemoteCommandCenter
- (void)addMediaPlayerRemoteCommands{
MPRemoteCommandCenter* commandCenter = [MPRemoteCommandCenter sharedCommandCenter];
MPRemoteCommand* pauseCommand = [commandCenter pauseCommand];
[pauseCommand setEnabled:YES];
[pauseCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
[self pause];
return MPRemoteCommandHandlerStatusSuccess;
}];
MPRemoteCommand* playCommand = [commandCenter playCommand];
[playCommand setEnabled:YES];
[playCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
[self play];
return MPRemoteCommandHandlerStatusSuccess;
}];
if (@available(ios 9.1, *)) {
MPRemoteCommand* changeProgressCommand = [commandCenter changePlaybackPositionCommand];
[changeProgressCommand setEnabled:YES];
[changeProgressCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
MPChangePlaybackPositionCommandEvent * playbackPositionEvent = (MPChangePlaybackPositionCommandEvent *)event;
CMTime time = CMTimeMakeWithSeconds(playbackPositionEvent.positionTime, self.player.currentItem.duration.timescale);
[self seekToTime:time];
return MPRemoteCommandHandlerStatusSuccess;
}];
}
}
到这里基本就已经实现了锁屏控制,需要注意的是,在界面销毁时,需要向MPRemoteCommandCenter注销代理,否则会导致界面在内存中无法销毁。
- (void)removeMediaPlayerRemoteCommands{
MPRemoteCommandCenter* commandCenter = [MPRemoteCommandCenter sharedCommandCenter];
[[commandCenter playCommand] removeTarget:self];
if (@available(iOS 9.1, *)) {
[[commandCenter pauseCommand] removeTarget:self];
}
[[commandCenter changePlaybackPositionCommand] removeTarget:self];
}