前言
在默認(rèn)環(huán)境下App被切換到后臺(tái)時(shí),音樂的就停止播放了,但音樂類App的一般都會(huì)需要在后臺(tái)繼續(xù)播放,這樣用戶就可以一邊聽音樂,一邊操作其他的App。對(duì)于這種情況我們可以對(duì)App做一些簡單的配置,實(shí)現(xiàn)后臺(tái)播放功能。當(dāng)app切換到后臺(tái),用戶就無法控制和查看app當(dāng)前播放歌曲了。這個(gè)對(duì)于用戶來說并不是很友好。既然是后臺(tái)播放,那么就應(yīng)該提供便捷的播放控制方式。iOS系統(tǒng)已經(jīng)預(yù)留了接口,允許開發(fā)者在鎖屏界面顯示播放歌曲信息(以下稱為鎖屏封面),以及在底部菜單欄提供播放控制器。下面我們就來給App添加這些功能吧。
一、后臺(tái)播放
設(shè)置App的plist,使app可以在后臺(tái)播放音樂。
myApp-Info.plist中添加UIBackgroundModes鍵值,添加子鍵值為audio。
然后再程序中添加入下代碼:
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setActive:YES error:nil];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
二、添加播放控制器(Remote Control Events)
首先我們要告訴系統(tǒng),我要接受系統(tǒng)的播放控制消息,這樣系統(tǒng)才會(huì)給我們發(fā)送播放控制命令。流程是這樣的:
App啟動(dòng) -> 告訴系統(tǒng)我需要接受播放控制消息 -> 等待 -> 用戶點(diǎn)擊系統(tǒng)播放控制器按鈕 -> 系統(tǒng)傳遞消息給App -> 我們接受到消息,做出相應(yīng)的響應(yīng)。
想要接收播放控制消息,我們必須要做三件事:
- 成為Frist Responder
- 請(qǐng)求系統(tǒng),要求開始監(jiān)聽播放控制消息(Remote Control Events)
- 開始播放音頻。
請(qǐng)注意第三點(diǎn),我們的App必須在開始播放音頻后,才能收到控制消息。否則,即使你滿足了前兩點(diǎn),也無法接收到控制消息。
//AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//...
//告訴系統(tǒng),我們要接受遠(yuǎn)程控制事件
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
}
- (BOOL)canBecomeFirstResponder
{
return YES;
}
//響應(yīng)遠(yuǎn)程音樂播放控制消息
- (void)remoteControlReceivedWithEvent:(UIEvent *)receivedEvent {
if (receivedEvent.type == UIEventTypeRemoteControl) {
switch (receivedEvent.subtype) {
case UIEventSubtypeRemoteControlTogglePlayPause:
[[PlayController sharedInstance] pause];
NSLog(@"RemoteControlEvents: pause");
break;
case UIEventSubtypeRemoteControlNextTrack:
[[PlayController sharedInstance] playModeNext];
NSLog(@"RemoteControlEvents: playModeNext");
break;
case UIEventSubtypeRemoteControlPreviousTrack:
[[PlayController sharedInstance] playPrev];
NSLog(@"RemoteControlEvents: playPrev");
break;
default:
break;
}
}
}
播放音頻的代碼,這里給出一段簡單的示例:
- (void)playBtnClicked
{
NSError *error = nil;
NSString *path = [[NSBundle mainBundle] pathForResource:@"music" ofType:@"mp3"];
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:path] error:&error];
if (error) {
NSLog(@"Error:%@", [error localizedDescription]);
}
[player play];
}
在開始播放音頻后,使用耳機(jī)線控的播放暫停等按鍵,或者鎖屏封面上的播放控制按鍵,就能夠收到控制消息了。
關(guān)于耳機(jī)線控的一點(diǎn)說明
蘋果耳機(jī)的線控上有三個(gè)按鈕:加號(hào),中部,減號(hào)。其中加號(hào)和減號(hào)是用于控制音量,這兩個(gè)按鈕點(diǎn)擊是收不到消息的——UIEventSubtype沒有音量改變的事件類型。而中部按鈕的點(diǎn)擊,是可以收到消息的,按一下是播放/暫停切換,快按兩下是播放下一首,快按三下是播放上一首,快按兩下并摁住是快進(jìn),快按三下并摁住是快退。
三、在鎖屏界面顯示播放歌曲信息
代碼如下,其實(shí)就是設(shè)置一個(gè)全局變量的值,當(dāng)系統(tǒng)處于音樂播放狀態(tài)時(shí),鎖屏界面就會(huì)將NowPlayingInfo中的信息展示出來??上У氖牵@里的定制性不是太強(qiáng),例如歌曲圖片無法平鋪整個(gè)屏幕大小,根據(jù)我的測試,歌曲圖片在320×320時(shí),可以完整顯示在屏幕中央位置,兩側(cè)不會(huì)留下黑邊。
Class playingInfoCenter = NSClassFromString(@"MPNowPlayingInfoCenter");
if (playingInfoCenter) {
NSMutableDictionary *songInfo = [[NSMutableDictionary alloc] init];
UIImage *image = [UIImage imageNamed:@"image"];
MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc] initWithImage:image];
//歌曲名稱
[songInfo setObject:@"深夜地下鐵" forKey:MPMediaItemPropertyTitle];
//演唱者
[songInfo setObject:@"陶鈺玉" forKey:MPMediaItemPropertyArtist];
//專輯名
[songInfo setObject:@"深夜地下鐵" forKey:MPMediaItemPropertyAlbumTitle];
//專輯縮略圖
[songInfo setObject:albumArt forKey:MPMediaItemPropertyArtwork];
[songInfo setObject:[NSNumber numberWithDouble:[audioY getCurrentAudioTime]] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime]; //音樂當(dāng)前已經(jīng)播放時(shí)間
[songInfo setObject:[NSNumber numberWithFloat:1.0] forKey:MPNowPlayingInfoPropertyPlaybackRate];//進(jìn)度光標(biāo)的速度 (這個(gè)隨 自己的播放速率調(diào)整,我默認(rèn)是原速播放)
[songInfo setObject:[NSNumber numberWithDouble:[audioY getAudioDuration]] forKey:MPMediaItemPropertyPlaybackDuration];//歌曲總時(shí)間設(shè)置
// 設(shè)置鎖屏狀態(tài)下屏幕顯示音樂信息
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:songInfo];
}
經(jīng)過了如上配置后,程序應(yīng)該就能夠正常顯示了。
四、遇到的問題
-
1.只添加MPMediaItemPropertyPlaybackDuration(歌曲總時(shí)間)
問題:不顯示當(dāng)前進(jìn)度
解決:添加MPMediaItemPropertyPlaybackDuration同時(shí)也出現(xiàn)問題,剩余時(shí)間每次減2秒
-
2.添加了MPMediaItemPropertyPlaybackDuration和MPNowPlayingInfoPropertyElapsedPlaybackTime
問題:出現(xiàn)了剩余時(shí)間每次減2秒的情況
解決:要添加MPNowPlayingInfoPropertyPlaybackRate就可以
-
3.暫?;謴?fù)播放更新 鎖屏進(jìn)度條
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:[[MPNowPlayingInfoCenter defaultCenter] nowPlayingInfo]];
[dict setObject:[NSNumber numberWithDouble:audioPlayer.playableDuration] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime]; //音樂當(dāng)前已經(jīng)過時(shí)間
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:dict];