iOS 4開(kāi)始引入的multitask,我們可以實(shí)現(xiàn)像ipod程序那樣在后臺(tái)播放音頻了。如果音頻操作是用蘋(píng)果官方的AVFoundation.framework實(shí)現(xiàn),像用AvAudioPlayer,AvPlayer播放的話,要實(shí)現(xiàn)完美的后臺(tái)音頻播放,依據(jù)app的功能需要,可能需要實(shí)現(xiàn)幾個(gè)關(guān)鍵的功能。
首先,播放音頻之前先要設(shè)置AVAudioSession模式,通常只用來(lái)播放的App可以設(shè)為AVAudioSessionCategoryPlayback即可。模式意義及其他模式請(qǐng)參考文檔。
[plain] view plaincopyprint?
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
[session setActive:YES error:nil];
1。通知OS該app支持background audio。缺省情況下,當(dāng)按下home鍵時(shí),當(dāng)前正在運(yùn)行的程序被suspend,狀態(tài)從active變成in-active,也就是說(shuō)如果正在播放音頻,按下HOME后就會(huì)停止。這里需要讓app在按在HOME后,轉(zhuǎn)到后臺(tái)運(yùn)行而非被suspend,解決辦法是在程序的-info.plist中增加required background modes這個(gè)key項(xiàng),并選擇App plays audio這個(gè)value項(xiàng)。
2。現(xiàn)在按下HOME鍵后,程序退到后臺(tái),但是聲音仍在播放。但是如果要實(shí)現(xiàn)播放列表的依次播放、循環(huán)播放,即放完一首后自動(dòng)切換到下一首,問(wèn)題來(lái)了,當(dāng)App在后臺(tái)放完一首后,就會(huì)停下來(lái)。原因是在后臺(tái)運(yùn)行時(shí),一旦聲音停下來(lái),程序也隨之suspend,因此在切換文件加載的間隙,程序就會(huì)被suspend。曾經(jīng)有山寨的解決辦法是專(zhuān)門(mén)起一個(gè)player的實(shí)例連續(xù)不停的放同一無(wú)聲音片斷,阻止程序被suspend。這里提供的方法是通過(guò)申請(qǐng)后臺(tái)taskID達(dá)到后臺(tái)切換播放文件的功能。
即聲明后臺(tái)task id,并通過(guò)beginBackgroundTaskWithExpirationHandler將App設(shè)為后臺(tái)Task,達(dá)到持續(xù)后臺(tái)運(yùn)行的目的。我們知道一般情況下,按HOME將程序送到后臺(tái),可以有5或10秒時(shí)間可以進(jìn)行一些收尾工作,具體時(shí)間[[UIApplication sharedApplication] backgroundTimeRemaining]返回值。超時(shí)后app會(huì)被suspend,現(xiàn)在要做的就是用[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL]開(kāi)始后臺(tái)任務(wù),可以將后臺(tái)運(yùn)行超時(shí)時(shí)間長(zhǎng)時(shí)間的延長(zhǎng),具體延長(zhǎng)多少時(shí)間還是見(jiàn)返回值,總之對(duì)于放段時(shí)間音樂(lè)應(yīng)該夠了。另一個(gè)問(wèn)題是每個(gè)開(kāi)始的后臺(tái)任務(wù),都必須用endBackgroundTask來(lái)結(jié)束。 因此,在每次開(kāi)始播放后啟動(dòng)新的后臺(tái)任務(wù),同時(shí)結(jié)束上一個(gè)后臺(tái)任務(wù):
首先,要在viewdidload中
[plain] view plaincopyprint?
[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
否則,無(wú)法切換到下一首,接下來(lái)
[plain] view plaincopyprint?
UIBackgroundTaskIdentifier newTaskId = UIBackgroundTaskInvalid;
[avPlayer play];
newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];
if (newTaskId != UIBackgroundTaskInvalid && oldTaskId != UIBackgroundTaskInvalid) {
[[UIApplication sharedApplication] endBackgroundTask: oldTaskId];}
oldTaskId = newTaskId;
當(dāng)然,還有更方便的辦法就是在resignActive時(shí)beginBackgroundTaskWithExpirationHandler:并在BecomeActive中endBackgroundTask:
3。我們知道,ipod播放程序在后臺(tái)時(shí),雙擊HOME鍵,會(huì)有個(gè)控制界面,可以對(duì)它進(jìn)行播放控制。
如果您想讓您的app可以像ipod一樣在后臺(tái)也可以方便的通過(guò)雙擊HOME鍵來(lái)控制,就要用到遠(yuǎn)程控制事件了。
首先在viewdidload等初始化的地方聲明App接收遠(yuǎn)程控制事件,并在相應(yīng)地方結(jié)束聲明
[plain] view plaincopyprint?
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
}
- (void) viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[UIApplication sharedApplication] endReceivingRemoteControlEvents];
[self resignFirstResponder];
}
定義
[plain] view plaincopyprint?
- (BOOL)canBecomeFirstResponder
{
return YES;
}
最后定義 remoteControlReceivedWithEvent,處理具體的播放、暫停、前進(jìn)、后退等具體事件
[plain] view plaincopyprint?
- (void) remoteControlReceivedWithEvent: (UIEvent *) receivedEvent {
if (receivedEvent.type == UIEventTypeRemoteControl) {
switch (receivedEvent.subtype) {
case UIEventSubtypeRemoteControlTogglePlayPause:
[self playButtonPressed:playButton];
[self testing];
break;
case UIEventSubtypeRemoteControlPreviousTrack:
[self rewButtonReleased:(UIButton *)rewButton];
break;
case UIEventSubtypeRemoteControlNextTrack:
[self ffwButtonReleased:(UIButton *)ffwButton];
break;
default:
break;
}
}
}
4. 至此,您有播放App已經(jīng)相當(dāng)完美了,還有最后一個(gè)問(wèn)題,那就是當(dāng)用戶使用耳機(jī)時(shí),問(wèn)題又來(lái)了。系統(tǒng)默認(rèn)當(dāng)插入耳機(jī)時(shí),正在播放的聲音不中斷,直接切換到耳機(jī)播放,而當(dāng)拔出耳機(jī)時(shí),播放停止。如果這種行為滿足您的要求,那OK,否則您就需要進(jìn)一步研究耳機(jī)檢測(cè)和聲音路由切換的問(wèn)題。