支持后台播放的音频、视频开发中遇到的问题

1、音频想要支持后台播放,需要进行一些设置,申请响应的后台权限:附后台播放设置链接
2、因为APP内有视频课程,所以申请了后台权限以后视频也可以后台、锁屏播放(播放视频的声音),这里需要根据自己的需求单独进行处理。
3、申请后台、锁屏播放以后,主要的问题就是通知中心的控制问题,特别是当视频和音频同时存在时,需要进行相应的处理,才能展示出想要的效果。

MPNowPlayingInfoCenter //更新控制信息 MPRemoteCommandCenter//进行远程控制 //文章更新:MPRemoteCommandCenter

AudioPlayer 与VideoPlayer 与 后台播放
出现的问题如下:
(1)APP内播放VideoPlayer,发现没有在Video相关的页面写“MPNowPlayingInfoCenter”与“MPRemoteCommandCenter”相关的代码,通知中心居然有了响应的播放信息,而且远程控制居然还管用。
(2)APP内首次播放过Video以后,再播放Audio,发现通知中心的音乐控制台居然不显示了,再次播放Video也不显示
出现这个问题的主要原因出在AVPlayerViewController,IOS 10增加了一个属性
/*! @property updatesNowPlayingInfoCenter @abstract Whether or not the now playing info center should be updated. Default is YES. */ @property (nonatomic) BOOL updatesNowPlayingInfoCenter API_AVAILABLE(ios(10.0));

正是因为有了这个属性,当我们播放Video时,才会出现自动更新NowPlayingInfoCenter,在锁屏、后台时,才会显示出相关的播放信息
所以,当我们需要在APP内播放视频时,设置属性
AVPlayerViewController *playerVC =[[AVPlayerViewController alloc] init]; playerVC.updatesNowPlayingInfoCenter = NO;

这样播放视频的时候,就不会更新NowPlayingInfoCenter的相关信息。
(3)然后,嗯嗯,又出现了新的问题
在APP内,首先播放一个音频,NowPlayingInfoCenter更新了有关的信息。在音频播放中,我们点击播放了一个视频,音频被暂停(产品需求)。然后发现,NowPlayingInfoCenter还是音频的相关信息,而且进度条还是前进,播放时间还在更新。由此可以推断,NowPlayingInfoCenter是自己有一个Timer,进行进度条和播放时间的更新。
我参考了市面上几款常见的APP,看看他们是怎么做的(操作完全相同,先在APP内播放一个音频,然后在音频播放时,再播放一个视频)
网易云音乐:NowPlayingInfoCenter 保持着上一个音频的相关音乐信息和进度,播放按钮显示“播放中”,但是播放时间和进度条 不继续变化。点击播放控制按钮,按钮变为“暂停”,再点击,视频声音停止,继续播放音频音乐。
支持后台播放的音频、视频开发中遇到的问题
文章图片
网易云音乐 喜马拉雅:NowPlayingInfoCenter 保存着上一个音频相关额信息,进度条和播放时间仍在持续更新中,嗯嗯,就是这样的。播放按钮显示“播放中”,点击播放控制按钮,按钮变为“暂停”,视频声音停止,继续播放音频音乐。
支持后台播放的音频、视频开发中遇到的问题
文章图片
喜马拉雅 知乎:知乎有视频课程与音频课程,可以试听;NowPlayingInfoCenter 不显示播放信息,进度条和播放时间也不显示。播放按钮显示“播放中”,点击播放控制按钮,按钮变为“暂停”,再点击,没有播放音频音乐,按钮短暂变换为“播放”,然后变成“暂停”。
支持后台播放的音频、视频开发中遇到的问题
文章图片
知乎 我们自己的实现效果:NowPlayingInfoCenter 不显示播放信息,进度条和播放时间也不显示。播放控制按钮也不可点击。
支持后台播放的音频、视频开发中遇到的问题
文章图片
LOFTY
在视频点击播放时,调用下面的代码:
- (void)setupLockScreenControlInfo {MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter]; // 锁屏播放 MPRemoteCommand *playCommand = commandCenter.playCommand; playCommand.enabled = NO; [playCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) { return MPRemoteCommandHandlerStatusCommandFailed; }]; // 锁屏暂停 MPRemoteCommand *pauseCommand = commandCenter.pauseCommand; pauseCommand.enabled = NO; [pauseCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) { return MPRemoteCommandHandlerStatusCommandFailed; }]; MPRemoteCommand *stopCommand = commandCenter.stopCommand; stopCommand.enabled = NO; [stopCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) { return MPRemoteCommandHandlerStatusCommandFailed; }]; // 播放和暂停按钮(耳机控制) MPRemoteCommand *playPauseCommand = commandCenter.togglePlayPauseCommand; playPauseCommand.enabled = NO; [playPauseCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) { return MPRemoteCommandHandlerStatusCommandFailed; }]; // 拖动进度条 if (@available(iOS 9.1, *)) { MPRemoteCommand *changePlaybackPositionCommand = commandCenter.changePlaybackPositionCommand; changePlaybackPositionCommand.enabled = NO; [changePlaybackPositionCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) { return MPRemoteCommandHandlerStatusCommandFailed; }]; } else { // Fallback on earlier versions } }- (void)setupLockScreenMediaInfo { //给MPNowPlayingInfoCenter传递空信息 MPNowPlayingInfoCenter *playingCenter = [MPNowPlayingInfoCenter defaultCenter]; NSMutableDictionary *playingInfo = [NSMutableDictionary new]; [playingCenter setNowPlayingInfo:playingInfo]; }

当我们重新点击播放一个音频时
//把MPRemoteCommandCenter的控制enabled = YES //写在viewWillAppear - (void) setRemoteControlCmmmentEnable { MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter]; commandCenter.playCommand.enabled = YES; commandCenter.pauseCommand.enabled = YES; commandCenter.stopCommand.enabled = YES; commandCenter.changePlaybackPositionCommand.enabled = YES; }

【支持后台播放的音频、视频开发中遇到的问题】注:在工程中,AudioPlayer 是一个单例, MPRemoteCommandCenter的相关控制信息也只能调用一次,若多次调用,点击事件就会响应多次。So,这里只设置 enable。

    推荐阅读