詳情請查看Demo,如果您覺得對您有幫助的話,別忘了Star一下喲,如果有什麼問題請指正。
如何開啓後臺播放功能且程序不會掛起
當應用退到後臺或者鎖屏狀態下,過段時間程序就會被掛起,這時我們就需要開啓一個後臺服務來防止後臺程序掛起,我是通過一個定時器來開啓服務的。直接上代碼。
step1: 首先開啓後臺模式中的音頻,如下圖
step2: 在AppDelegate.m文件中導入頭文件 #import <AVFoundation/AVFoundation.h>
#import <AVFoundation/AVFoundation.h>
@interface AppDelegate ()
@property (strong, nonatomic) NSTimer *backgroundTime;
@property (nonatomic, assign) UIBackgroundTaskIdentifier bgTask;
@end
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
//程序失去焦點的時候 開啓後臺服務
[self openServiceWhenBack];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
//當程序進入前臺的時候結束後臺任務
[self endBackgroundTask];
}
#pragma mark ---------------------------- 開啓一個後臺任務
- (void)openServiceWhenBack{
UIApplication* app = [UIApplication sharedApplication];
self.bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:self.bgTask];
self.bgTask = UIBackgroundTaskInvalid;
}];
//開啓定時器 不斷向系統請求後臺任務執行的時間
self.backgroundTime = [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector(applyForMoreTime) userInfo:nil repeats:YES];
[self.backgroundTime fire];
}
//申請後臺任務
-(void)applyForMoreTime {
//如果系統給的剩餘時間小於60秒 就終止當前的後臺任務,再重新初始化一個後臺任務,重新讓系統分配時間,這樣一直循環下去,保持APP在後臺一直處於active狀態。
if ([UIApplication sharedApplication].backgroundTimeRemaining < 60) {
[[UIApplication sharedApplication] endBackgroundTask:self.bgTask];
self.bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:self.bgTask];
self.bgTask = UIBackgroundTaskInvalid;
}];
}
}
#pragma mark ---------------------------- 結束一個後臺任務
- (void)endBackgroundTask {
UIApplication *app = [UIApplication sharedApplication];
[app endBackgroundTask:self.bgTask];
self.bgTask = UIBackgroundTaskInvalid;
if (self.backgroundTime) {
// 結束計時
[self.backgroundTime invalidate];
self.backgroundTime = nil;
}
}
以上是開啓後臺服務的操作,這樣就能避免程序被掛起
接下來說明一下如果有音樂播放器播放的時候如何播放自己的音頻問題
step1: 初始化播放器(初始化的時候一定要把播放器設置爲全局變量,否則會沒有聲音),這裏我用的是懶加載初始化
///懶加載播放器
- (AVAudioPlayer *)voicePlayer{
if (!_voicePlayer) {
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"defaultAudio" ofType:@"mp3"];
NSURL *fileUrl = [NSURL fileURLWithPath:filePath];
_voicePlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileUrl error:nil];;
_voicePlayer.volume = 1;
//這裏的代理如果要用到就可以設置,沒有用到就不用設置
_voicePlayer.delegate = self;
}
return _voicePlayer;
}
播放音頻
- (void)viewDidLoad {
[super viewDidLoad];
//播放音樂
[self.voicePlayer play];
}
停止播放音頻
- (void)stopPlayVoiceAction{
//停止播放音頻
[self.voicePlayer stop];
}
播放完成代理 (其他代理方法請自行處置,這裏只舉例播放完成事件)
#pragma mark ------------------------ AVAudioPlayer的代理事件
//播放完成
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
if (flag) {
//播放完成後繼續從頭播放
[self.voicePlayer play];
}
}
step2: 後臺播放音頻及同時播放音樂播放器
這裏就需要介紹一下AVAudioSession類,在這裏請參考iOS 音頻-AVAudioSession文章,感謝簡書作者安東_Ace,這篇文章介紹的比較詳細。
當程序進入後臺的時候,我們需要設置AVAudioSession爲後臺模式並且爲活躍狀態,
[[AVAudioSession sharedInstance] setActive:YES error:nil];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
這個時候我們的音頻文件就會一直在後臺播放了。
但是這種情況下假如我們正在聽音樂,當我們的音頻播放的時候音樂就會被停止,如果想繼續聽音樂我們就的需要把音樂重新點擊播放。那我們能不能像地圖導航一樣實現在能聽音樂的時候還能收到語音播報呢,而且這是語音播報的聲音被放大,音樂聲音被調小,而且語音播報完成後就恢復正常音樂音量呢,答案是肯定的。
這個時候我們就需要設置AVAudioSession的options了。
//AVAudioSessionCategoryOptionMixWithOthers:允許其他音頻文件同時播放
//AVAudioSessionCategoryOptionDuckOthers:當播放本音頻時其他音頻音量變小
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers | AVAudioSessionCategoryOptionDuckOthers error:nil];
如果音頻播放完後,需要重新把音樂聲音恢復,在音頻播放完後或者自己想要恢復的時候
[[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
這樣就能把音樂的聲音恢復了,類似地圖導航。