音頻鎖屏狀態(tài)下播放(2018-01-21)

? ? ? ? ?項(xiàng)目上線音頻播放后,仍然滿足不了廣大學(xué)員的需求,學(xué)員想要的是音頻能夠在鎖屏狀態(tài)下也能夠播放。于是和公司領(lǐng)導(dǎo)討論完成音頻的后臺播放功能,現(xiàn)在就將我所實(shí)現(xiàn)音頻鎖屏播放的過程和遇到的坑和大家分享一下。

1、首先是集成音頻播放器:(我把這個播放器放在了一個單利里面)

實(shí)現(xiàn)的代碼如下:

#pragma mark --添加在線播放器

- (void)addOnLinePlayer {

? ? WS(weakSelf)

? ? [[SKAVPlayerManager PlayerManager] replaceItemWithUrlString:self.onLinePlayerUrl type:@"zaixian"];


? ? __weak typeof(SKAVPlayerManager *) manager = [SKAVPlayerManager PlayerManager];

? ? [SKAVPlayerManager PlayerManager].statusBlock = ^(BOOL success) {

? ? ? ? if (success) {

? ? ? ? ? ? // 如果是暫停狀態(tài)則不進(jìn)行播放

? ? ? ? ? ? if (weakSelf.playerButton.selected != YES) {

? ? ? ? ? ? ? ? [manager playerPlay];

? ? ? ? ? ? ? ? [SKAVPlayerManager PlayerManager].player.rate = weakSelf.playerRate;

? ? ? ? ? ? }

? ? ? ? } else {

? ? ? ? }

? ? };

? ? // 添加時間監(jiān)聽

? ? self.myTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];

}

// 播放一段音頻

- (void)replaceItemWithUrlString:(NSString *)urlString type:(NSString *)readType {

? ? self.ccid = urlString;

? ? [_playerItem removeObserver:self forKeyPath:@"status"];

? ? _playerItem = nil;

? ? if ([readType isEqualToString:@"zaixian"]) {

? ? ? ? _playerItem = [[AVPlayerItem alloc] initWithURL:[NSURL URLWithString:urlString]];

? ? } else if ([readType isEqualToString:@"bendi"]){

? ? ? ? NSURL *audioURL = [NSURL fileURLWithPath:urlString];

? ? ? ? _playerItem = [[AVPlayerItem alloc] initWithURL:audioURL];

? ? }

? ? [_playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];

? ? [self.player replaceCurrentItemWithPlayerItem:_playerItem];

}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {

? ? if ([keyPath isEqualToString:@"status"]) {

? ? ? ? self.isNotify = YES;

? ? ? ? switch (self.player.status) {

? ? ? ? ? ? case AVPlayerStatusUnknown:

? ? ? ? ? ? ? ? // KVO:未知狀態(tài),此時不能播放

? ? ? ? ? ? ? ? if (self.statusBlock) {

? ? ? ? ? ? ? ? ? ? self.statusBlock(NO);

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? case AVPlayerStatusReadyToPlay:

? ? ? ? ? ? ? ? //KVO:準(zhǔn)備完畢,可以播放

? ? ? ? ? ? ? ? if (self.statusBlock) {

? ? ? ? ? ? ? ? ? ? self.statusBlock(YES);

? ? ? ? ? ? ? ? }

//? ? ? ? ? ? ? ? [self playerPlay];

//? ? ? ? ? ? ? ? [[NSNotificationCenter defaultCenter] postNotificationName:PlayerStatusNormal object:nil];

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? case AVPlayerStatusFailed:

? ? ? ? ? ? ? ? // KVO:加載失敗,網(wǎng)絡(luò)或者服務(wù)器出現(xiàn)問題

? ? ? ? ? ? ? ? if (self.statusBlock) {

? ? ? ? ? ? ? ? ? ? self.statusBlock(NO);

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? default:

? ? ? ? ? ? ? ? break;

? ? ? ? }

? ? }

}

2、時間進(jìn)度的控制如下以及進(jìn)度條的更新:

- (void)timerAction {

? ? if ([SKAVPlayerManager PlayerManager].player.currentTime.timescale == 0 || [SKAVPlayerManager PlayerManager].player.currentItem.duration.timescale == 0) {

? ? ? ? return;

? ? }

? ? // 獲得音樂總時長

? ? long long int totalTime = [SKAVPlayerManager PlayerManager].player.currentItem.duration.value / [SKAVPlayerManager PlayerManager].player.currentItem.duration.timescale;

? ? // 獲得當(dāng)前時間

? ? long long int currentTime = [SKAVPlayerManager PlayerManager].player.currentTime.value / [SKAVPlayerManager PlayerManager].player.currentTime.timescale;


? ? currentTimeLable.text = [NSString stringWithFormat:@"%02lld:%02lld", currentTime / 60, currentTime % 60];

? ? orignalTimeLable.text = [NSString stringWithFormat:@"%02lld:%02lld", totalTime / 60, totalTime % 60];

? ? audioSlider.maximumValue = totalTime;

? ? audioSlider.minimumValue = 0;

? ? audioSlider.value = currentTime;

? ? if (currentTime == totalTime) {

? ? ? ? // 進(jìn)行下一曲播放

? ? ? ? [self nextButtonAction:[UIButton new]];

? ? }

? ? if (@available(iOS 11.0, *)) {

? ? } else {

? ? ? ? if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {

? ? ? ? ? ? [self onLineRemoteControl];

? ? ? ? }

? ? }

}


3、這個時候音頻就能正常播放了,在保證音頻能正常播放的對工程進(jìn)行設(shè)置:

先要注冊后臺播放:


然后在info.plist文件里面進(jìn)行設(shè)置:

App plays audio or streams audio/video using AirPlay

4、當(dāng)程序進(jìn)入后臺和前臺的時候通過通知監(jiān)聽所處的狀態(tài):

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didEnterBackground) name:UIApplicationWillResignActiveNotification object:nil];

? ? [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil];

- (void)didEnterBackground {

????????[self onLineRemoteControl];

}

// 在線后臺播放

- (void)onLineRemoteControl {

? ? ? ? MPNowPlayingInfoCenter *center = [MPNowPlayingInfoCenter defaultCenter];

? ? ? ? UIImage *lockImage = [UIImage imageNamed:@"photo1.png"];


? ? ? ? MPMediaItemArtwork *artwork =

? ? ? ? [[MPMediaItemArtwork alloc] initWithImage:lockImage];

? ? ? ? NSDictionary *mediaDict =

? ? ? ? @{

? ? ? ? ? MPMediaItemPropertyTitle: self.model.title,

? ? ? ? ? MPMediaItemPropertyMediaType: @(MPMediaTypeAnyAudio),

? ? ? ? ? MPMediaItemPropertyPlaybackDuration:

? ? ? ? ? ? ? @([SKAVPlayerManager PlayerManager].player.currentItem.duration.value / [SKAVPlayerManager PlayerManager].player.currentItem.duration.timescale),

? ? ? ? ? MPNowPlayingInfoPropertyPlaybackRate: @(1.0),

? ? ? ? ? MPNowPlayingInfoPropertyElapsedPlaybackTime:

? ? ? ? ? ? ? @([SKAVPlayerManager PlayerManager].player.currentTime.value / [SKAVPlayerManager PlayerManager].player.currentTime.timescale),

? ? ? ? ? MPMediaItemPropertyAlbumArtist:self.subscribeModel.title,

? ? ? ? ? MPMediaItemPropertyArtist:self.subscribeModel.title,

? ? ? ? ? MPMediaItemPropertyArtwork: artwork};


? ? ? ? [center setNowPlayingInfo:mediaDict];


? ? ? ? //讓app支持接受遠(yuǎn)程控制事件

? ? ? ? [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];

}

- (void)?didBecomeActive {

//讓app結(jié)束接受遠(yuǎn)程控制事件

? ? [[UIApplication sharedApplication] endReceivingRemoteControlEvents];

}

5、這個時候發(fā)現(xiàn)是可以進(jìn)行后臺播放的,但是進(jìn)度條無法調(diào)整,為了能夠調(diào)整進(jìn)度條需要添加遠(yuǎn)程控制命令中心:

#pragma mark --鎖屏界面開啟和監(jiān)控遠(yuǎn)程控制事件

- (void)createRemoteCommandCenter{

? ? //遠(yuǎn)程控制命令中心 iOS 7.1 之后? 詳情看官方文檔:https://developer.apple.com/documentation/mediaplayer/mpremotecommandcenter

? ? MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter];

? ? //? ? commandCenter.togglePlayPauseCommand 耳機(jī)線控的暫停/播放

? ? [commandCenter.pauseCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {

? ? ? ? return MPRemoteCommandHandlerStatusSuccess;

? ? }];

? ? [commandCenter.playCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {

? ? ? ? return MPRemoteCommandHandlerStatusSuccess;

? ? }];

? ? [commandCenter.previousTrackCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {

? ? ? ? NSLog(@"上一首");

? ? ? ? return MPRemoteCommandHandlerStatusSuccess;

? ? }];

? ? [commandCenter.nextTrackCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {

? ? ? ? NSLog(@"下一首");

? ? ? ? return MPRemoteCommandHandlerStatusSuccess;

? ? }];

? ? //在控制臺拖動進(jìn)度條調(diào)節(jié)進(jìn)度(仿QQ音樂的效果)

? ? [commandCenter.changePlaybackPositionCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {

? ? ? ? ? ? CMTime totlaTime = [SKAVPlayerManager PlayerManager].player.currentItem.duration;

? ? ? ? ? ? MPChangePlaybackPositionCommandEvent * playbackPositionEvent = (MPChangePlaybackPositionCommandEvent *)event;

? ? ? ? ? ? [[SKAVPlayerManager PlayerManager].player seekToTime:CMTimeMake(totlaTime.value*playbackPositionEvent.positionTime/CMTimeGetSeconds(totlaTime), totlaTime.timescale) completionHandler:^(BOOL finished) {

? ? ? ? ? ? }];

? ? ? ? return MPRemoteCommandHandlerStatusSuccess;

? ? }];

}

這個時候就都實(shí)現(xiàn)了所有的功能了我們所做的有如下截圖:


最后說下需要注意的幾點(diǎn):

1、使用changePlaybackPositionCommand進(jìn)行seekTime時候,控制中心的播放進(jìn)度條停止了下來 使用帶handler的回調(diào),在回調(diào)處再次對info進(jìn)行進(jìn)度條的更新

2、一定要注意block的循環(huán)引用問題,不然會引起內(nèi)存暴漲。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容