iOS 4開始引入的multitask,咱們能夠實現像ipod程序那樣在後臺播放音頻了。若是音頻操做是用蘋果官方的AVFoundation.framework實現,像用AvAudioPlayer,AvPlayer播放的話,要實現完美的後臺音頻播放,依據app的功能須要,可能須要實現幾個關鍵的功能。html
首先,播放音頻以前先要設置AVAudioSession模式,一般只用來播放的App能夠設爲AVAudioSessionCategoryPlayback便可。模式意義及其餘模式請參考文檔。ios
//後臺播放音頻設置 AVAudioSession *session = [AVAudioSession sharedInstance]; [session setActive:YES error:nil]; [session setCategory:AVAudioSessionCategoryPlayback error:nil];
1.通知IOS該app支持background audio。缺省狀況下,當按下home鍵時,當前正在運行的程序被suspend,狀態從active變成in-active,也就是說若是正在播放音頻,按下HOME後就會中止。這裏須要讓app在按在HOME後,轉到後臺運行而非被suspend,解決辦法是在程序的-info.plist中增長required background modes這個key項,並選擇App plays audio or streams audio/video using AirPlay這個value項(若是用過Xcode5.0,在TARGETS-Capabilities-Background Modes設置爲ON,勾選Audio and AirPlay選項)。spring
2.若是你在後臺播放使用的時加載網絡音頻,恰巧網速很慢,音頻被中止下來這時候程序也隨之suspend,曾經有山寨的解決辦法是專門起一個player的實例連續不停的放同一無聲音片段,阻止程序被suspend。這裏提供的方法是經過申請後臺taskID達到後臺切換播放文件的功能。
即便聲明taskID也最多隻能在後臺運行600秒鐘。(在ios7sdk中可使用NSURLSession來實現後臺緩衝)
(通常狀況下,按HOME將程序送到後臺,能夠有5或10秒時間能夠進行一些收尾工做,具體時間[[UIApplication sharedApplication] backgroundTimeRemaining]返回值,超時後app會被suspend。)api
3.ipod播放程序在後臺時,雙擊HOME鍵,會有個控制界面,能夠對它進行播放控制(暫停開始、上一曲、下一曲)。若是您想讓您的app能夠像ipod同樣在後臺也能夠方便的經過雙擊HOME鍵來控制(在ios7中是使用上拉菜單控制),就要用到遠程控制事件了。
首先在viewdidload等初始化的地方聲明App接收遠程控制事件,並在相應地方結束聲明網絡
- (void) viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [UIApplication sharedApplication] beginReceivingRemoteControlEvents]; [self becomeFirstResponder]; } - (void) viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [UIApplication sharedApplication] endReceivingRemoteControlEvents]; [self resignFirstResponder]; } - (BOOL)canBecomeFirstResponder { return YES; }
固然也不必定是在viewcontroller中,也能夠是在applicationDidEnterBackground:方法中開始接受遠程控制,applicationDidBecomeActive:中結束接受遠程控制,可是當前的appdelegate中要繼承與UIResponder,由於在激活遠程控制之後要把當前類變成第一響應,重寫canBecomeFirstResponder方法。session
最後定義 remoteControlReceivedWithEvent,處理具體的播放、暫停、前進、後退等具體事件app
//重寫父類方法,接受外部事件的處理 - (void) remoteControlReceivedWithEvent: (UIEvent *) receivedEvent { if (receivedEvent.type == UIEventTypeRemoteControl) { switch (receivedEvent.subtype) { case UIEventSubtypeRemoteControlTogglePlayPause: [self playAndStopSong:self.playButton]; break; case UIEventSubtypeRemoteControlPreviousTrack: [self playLastButton:self.lastButton]; break; case UIEventSubtypeRemoteControlNextTrack: [self playNextSong:self.nextButton]; break; case UIEventSubtypeRemoteControlPlay: [self playAndStopSong:self.playButton]; break; case UIEventSubtypeRemoteControlPause: [self playAndStopSong:self.playButton]; break; default: break; } } }
其它外部事件也可經過這種方式實現,如「搖一搖」響應等。ide
4. 至此,您有播放App已經基本完成了,其次插拔耳機是否響應中止播放時間須要進一步研究耳機檢測和聲音路由切換的問題,再次不詳細講述。函數
5. 還有一些開發者可能會發現,有一些音視頻app在定義的時候自定一些控件能夠調節系統的音量大小,不須要用戶調整音量按鈕。經查看相關的資料總結出有兩種方法:
一種是調用控件MPVolumeView在屏幕中建立一個音量條,拖動能夠改變系統的音量大小。
另外一種是使用MPMusicPlayerController類,能夠自定義控件調整系統音量的大小(可是在ios7sdk中已經被棄用,估計之後幾個版本中可能找不到這個方法了)。ui
MPMusicPlayerController *mpc = [MPMusicPlayerController applicationMusicPlayer]; mpc.volume = 0; //0.0~1.0
6. 在一些其餘的音樂播放軟件中如:酷我、qq音樂等,你會發在播放的時候,當設備鎖屏之後依然能夠看到用戶播放的音樂名稱、演唱者、專輯名稱、音樂時長、專輯圖片等信息。這些就須要在用戶切換完歌去的時候,在程序中設置信息了。
//設置鎖屏狀態,顯示的歌曲信息 -(void)configNowPlayingInfoCenter{ if (NSClassFromString(@"MPNowPlayingInfoCenter")) { NSDictionary *info = [self.musicList objectAtIndex:_playIndex]; NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; //歌曲名稱 [dict setObject:[info objectForKey:@"name"] forKey:MPMediaItemPropertyTitle]; //演唱者 [dict setObject:[info objectForKey:@"singer"] forKey:MPMediaItemPropertyArtist]; //專輯名 [dict setObject:[info objectForKey:@"album"] forKey:MPMediaItemPropertyAlbumTitle]; //專輯縮略圖 UIImage *image = [UIImage imageNamed:[info objectForKey:@"image"]]; MPMediaItemArtwork *artwork = [[MPMediaItemArtwork alloc] initWithImage:image]; [dict setObject:artwork forKey:MPMediaItemPropertyArtwork]; //音樂剩餘時長 [dict setObject:[NSNumber numberWithDouble:self.player.duration] forKey:MPMediaItemPropertyPlaybackDuration]; //音樂當前播放時間 在計時器中修改 //[dict setObject:[NSNumber numberWithDouble:0.0] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime]; //設置鎖屏狀態下屏幕顯示播放音樂信息 [[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:dict]; } }
上面的if (NSClassFromString(@」MPNowPlayingInfoCenter」))語句,說是爲了不了版本兼容問題,這個API貌似只出如今5裏面。
7. 下面就在計時器中不斷刷新鎖屏狀態下的播放進度條了。
//計時器修改進度 - (void)changeProgress:(NSTimer *)sender{ if(self.player){ //當前播放時間 NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:[[MPNowPlayingInfoCenter defaultCenter] nowPlayingInfo]]; [dict setObject:[NSNumber numberWithDouble:self.player.currentTime] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime]; //音樂當前已通過時間 [[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:dict]; } }
8. 當前的不少常見的播放器均可以在鎖屏狀態下顯示顯示歌詞,通過一番查找後,終於找到方法(詳情:點擊查看),大體就是根據播放的時間和歌詞顯示時間,利用計時器不斷的用歌詞和專輯封面合成圖片,達到顯示歌詞的效果。還有就是在屏幕變暗中止這一操做、屏幕點亮的時候開始計時器,以節省電量和cpu,有兩種方法能夠監聽上述現象:
一種是監聽內核層DarwinNotification,在Darwin中,有不少的系統事件,但apple的api文檔描述這些api使用有限制,也就是灰色地帶的api,因此能不用則不用;
另外一種方法能夠經過notify_get_state來獲取com.apple.springboard.hasBlankedScreen 的狀態值,經過狀態值咱們能夠判斷屏幕狀態,屏幕亮或者暗系統會給出不一樣狀態值,而後根據狀態值,經過NotificationCenter發送消息通知給相應的函數處理。