最近在做音樂播放器巷折,要靜音狀態(tài)下播放,后臺播放崖咨,遠(yuǎn)程控制锻拘,鎖屏顯示,上拉菜單控制击蹲,來電中斷處理等署拟。
開啟后臺模式:
在TARGETS-Capabilities-Background Modes 勾選Audio,AirPay and Picture in Picture
在AppDelegate中
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//靜音狀態(tài)下播放
[[AVAudioSession sharedInstance] setActive:YES error:nil];
//處理電話打進(jìn)時中斷音樂播放
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(interruptionNotificationHandler:) name:AVAudioSessionInterruptionNotification object:nil];
//后臺播放
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
// 在App啟動后開啟遠(yuǎn)程控制事件, 接收來自鎖屏界面和上拉菜單的控制
[application beginReceivingRemoteControlEvents];
// 處理遠(yuǎn)程控制事件
[self remoteControlEventHandler];
self.window= [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
[self.window makeKeyAndVisible];
MusicListTableVC * vc = [[MusicListTableViewController alloc] init];
UINavigationController * nc = [[UINavigationController alloc] initWithRootViewController:vc];
self.window.rootViewController = nc;
return YES;
}
來電中斷處理:
//來電中斷處理
- (void)interruptionNotificationHandler:(NSNotification*)notification
{
NSDictionary *interuptionDict = notification.userInfo;
NSString *type = [NSString stringWithFormat:@"%@", [interuptionDict valueForKey:AVAudioSessionInterruptionTypeKey]];
NSUInteger interuptionType = [type integerValue];
if (interuptionType == AVAudioSessionInterruptionTypeBegan) {
//獲取中斷前音樂是否在播放
_played = [MusicPlayViewController shareMusicPlay].isPlaying;
NSLog(@"AVAudioSessionInterruptionTypeBegan");
}else if (interuptionType == AVAudioSessionInterruptionTypeEnded) {
NSLog(@"AVAudioSessionInterruptionTypeEnded");
}
if(_played)
{
//停止播放的事件
[[MusicPlayTools shareMusicPlay] musicPause];
_played=NO;
}else {
//繼續(xù)播放的事件
[[MusicPlayTools shareMusicPlay] musicPlay];
_played=YES;
}
}
- (void)applicationWillResignActive:(UIApplication *)application
{
NSLog(@"要掛起了。歌豺。推穷。");
//更新鎖屏信息
[[MusicPlayViewController shareMusicPlay] configNowPlayingInfoCenter];
}
- (void)applicationWillTerminate:(UIApplication *)application
{
// 在App要終止前結(jié)束接收遠(yuǎn)程控制事件, 也可以在需要終止時調(diào)用該方法終止
[application endReceivingRemoteControlEvents];
}
遠(yuǎn)程控制事件處理:
// 在需要處理遠(yuǎn)程控制事件的具體控制器或其它類中實現(xiàn)
- (void)remoteControlEventHandler
{
// 直接使用sharedCommandCenter來獲取MPRemoteCommandCenter的shared實例
MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter];
// 啟用播放命令 (鎖屏界面和上拉快捷功能菜單處的播放按鈕觸發(fā)的命令)
commandCenter.playCommand.enabled = YES;
// 為播放命令添加響應(yīng)事件, 在點擊后觸發(fā)
[commandCenter.playCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
[[MusicPlayTools shareMusicPlay] musicPlay];
[[MusicPlayViewController shareMusicPlay] configNowPlayingInfoCenter];
return MPRemoteCommandHandlerStatusSuccess;
}];
// 播放, 暫停, 上下曲的命令默認(rèn)都是啟用狀態(tài), 即enabled默認(rèn)為YES
[commandCenter.pauseCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
//點擊了暫停
[[MusicPlayTools shareMusicPlay] musicPause];
[[MusicPlayViewController shareMusicPlay] configNowPlayingInfoCenter];
return MPRemoteCommandHandlerStatusSuccess;
}];
[commandCenter.previousTrackCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
//點擊了上一首
[[MusicPlayViewController shareMusicPlay] lastSongAction];
[[MusicPlayViewController shareMusicPlay] configNowPlayingInfoCenter];
return MPRemoteCommandHandlerStatusSuccess;
}];
[commandCenter.nextTrackCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
//點擊了下一首
[[MusicPlayViewController shareMusicPlay] nextSongButtonAction:nil];
[[MusicPlayViewController shareMusicPlay] configNowPlayingInfoCenter];
return MPRemoteCommandHandlerStatusSuccess;
}];
// 啟用耳機(jī)的播放/暫停命令 (耳機(jī)上的播放按鈕觸發(fā)的命令)
commandCenter.togglePlayPauseCommand.enabled = YES;
// 為耳機(jī)的按鈕操作添加相關(guān)的響應(yīng)事件
[commandCenter.togglePlayPauseCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
// 進(jìn)行播放/暫停的相關(guān)操作 (耳機(jī)的播放/暫停按鈕)
[[MusicPlayViewController shareMusicPlay] playPauseButtonAction:nil];
[[MusicPlayViewController shareMusicPlay] configNowPlayingInfoCenter];
return MPRemoteCommandHandlerStatusSuccess;
}];
}
鎖頻界面上所顯示的歌曲播放信息和圖片,控制中心上顯示的歌曲播放信息等类咧,這些信息的顯示都由MPNowPlayingInfoCenter類來控制馒铃。
首先#import <MediaPlayer/MPNowPlayingInfoCenter.h>然后調(diào)用MPNowPlayingInfoCenter的單例方法獲取實例,再把需要顯示的信息組織成Dictionary并賦值給nowPlayingInfo屬性就完成了痕惋。
其中常用的是MPNowPlayingInfoPropertyElapsedPlaybackTime和MPNowPlayingInfoPropertyPlaybackRate:
- MPNowPlayingInfoPropertyElapsedPlaybackTime表示已經(jīng)播放的時間区宇,用這個屬性可以讓NowPlayingCenter顯示播放進(jìn)度;
- MPNowPlayingInfoPropertyPlaybackRate表示播放速率值戳。通常情況下播放速率為1.0议谷,即真是時間的1秒對應(yīng)播放時間中的1秒;
這里需要解釋的是堕虹,NowPlayingCenter中的進(jìn)度刷新并不是由app不停的更新nowPlayingInfo來做的卧晓,而是根據(jù)app傳入的ElapsedPlaybackTime和PlaybackRate進(jìn)行自動刷新叶洞。例如傳入ElapsedPlaybackTime=120s,PlaybackRate=1.0禀崖,那么NowPlayingCenter會顯示2:00并且在接下來的時間中每一秒把進(jìn)度加1秒并刷新顯示衩辟。如果需要暫停進(jìn)度,傳入PlaybackRate=0.0即可波附。
所以每次播放暫停和繼續(xù)都需要更新NowPlayingCenter并正確設(shè)置ElapsedPlaybackTime和PlaybackRate否則NowPlayingCenter中的播放進(jìn)度無法正常顯示艺晴。
NowPlayingCenter的刷新時機(jī)
頻繁的刷新NowPlayingCenter并不可取,特別是在有Artwork的情況下掸屡。所以需要在合適的時候進(jìn)行刷新封寞。
依照我自己的經(jīng)驗下面幾個情況下刷新NowPlayingCenter比較合適:
- 當(dāng)前播放歌曲進(jìn)度被拖動時
- 當(dāng)前播放的歌曲變化時
- 播放暫停或者恢復(fù)時
- 當(dāng)前播放歌曲的信息發(fā)生變化時(例如Artwork仅财,duration等)
在刷新時可以適當(dāng)?shù)耐ㄟ^判斷app是否active來決定是否必須刷新以減少刷新次數(shù)狈究。
/**
* 設(shè)置鎖屏信息
*/
-(void)configNowPlayingInfoCenter
{
Class playingInfoCenter = NSClassFromString(@"MPNowPlayingInfoCenter");
if (playingInfoCenter) {
MusicInfoModel * model = [MusicPlayTools shareMusicPlay].model;
NSMutableDictionary *songInfo = [[NSMutableDictionary alloc] init];
UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"%ld", self.index + 1]];
MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc] initWithBoundsSize:image.size requestHandler:^UIImage * _Nonnull(CGSize size) {
return image;
}];
//歌曲名稱
[songInfo setObject:model.name forKey:MPMediaItemPropertyTitle];
//演唱者
[songInfo setObject:model.singer forKey:MPMediaItemPropertyArtist];
//專輯名
[songInfo setObject:@"專輯名" forKey:MPMediaItemPropertyAlbumTitle];
//專輯縮略圖
[songInfo setObject:albumArt forKey:MPMediaItemPropertyArtwork];
//音樂當(dāng)前已經(jīng)播放時間
NSInteger currentTime = [[MusicPlayTools shareMusicPlay] getCurTime];
[songInfo setObject:[NSNumber numberWithInteger:currentTime] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime];
//進(jìn)度光標(biāo)的速度 (這個隨 自己的播放速率調(diào)整,我默認(rèn)是原速播放)
[songInfo setObject:[NSNumber numberWithFloat:1.0] forKey:MPNowPlayingInfoPropertyPlaybackRate];
//歌曲總時間設(shè)置
NSInteger duration = [model.duration integerValue];
[songInfo setObject:[NSNumber numberWithInteger:duration] forKey:MPMediaItemPropertyPlaybackDuration];
//設(shè)置鎖屏狀態(tài)下屏幕顯示音樂信息
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:songInfo];
}
}