#######要想開啟后臺播放,需要兩步
- 開啟后臺模式:
- 設(shè)置AVAudioSession的類型為AVAudioSessionCategoryPlayback并且調(diào)用setActive::方法啟動(激活)會話。
AVAudioSession *audioSession=[AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
[audioSession setActive:YES error:nil];
#######為了支持拔耳機以后,自動暫停播放顽耳,需要添加遠程控制事件
前兩步是后臺播放所必須設(shè)置的,第三步主要用于接收遠程事件,如果這一步不設(shè)置雖讓也能夠在后臺播放烛亦,但是無法獲得音頻控制權(quán)(如果在使用當前應用之前使用其他播放器播放音樂的話,此時如果按耳機播放鍵或者控制中心的播放按鈕則會播放前一個應用的音頻)懂拾,并且不能使用耳機進行音頻控制煤禽。
第一步操作相信大家都很容易理解,如果應用程序要允許運行到后臺必須設(shè)置岖赋,正常情況下應用如果進入后臺會被掛起檬果,通過該設(shè)置可以讓應用程序繼續(xù)在后臺運行。
拔耳機監(jiān)聽操作
增加通知:
//添加通知唐断,拔出耳機后暫停播放
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(routeChange:) name:AVAudioSessionRouteChangeNotification object:nil];
通知方法:
/**
* 一旦輸出改變則執(zhí)行此方法
*
* @param notification 輸出改變通知對象
*/
-(void)routeChange:(NSNotification *)notification{
NSDictionary *dic=notification.userInfo;
int changeReason= [dic[AVAudioSessionRouteChangeReasonKey] intValue];
//等于AVAudioSessionRouteChangeReasonOldDeviceUnavailable表示舊輸出不可用
if (changeReason==AVAudioSessionRouteChangeReasonOldDeviceUnavailable) {
AVAudioSessionRouteDescription *routeDescription=dic[AVAudioSessionRouteChangePreviousRouteKey];
AVAudioSessionPortDescription *portDescription= [routeDescription.outputs firstObject];
//原設(shè)備為耳機則暫停
if ([portDescription.portType isEqualToString:@"Headphones"]) {
[self pause];
}
}
// [dic enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
// NSLog(@"%@:%@",key,obj);
// }];
}
記得要取消監(jiān)聽:
-(void)dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVAudioSessionRouteChangeNotification object:nil];
}
接收遠程事件
在appDelegate中的didFinishLaunchingWithOptions方法中添加:
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
來接收遠程控制事件
然后在viewController中选脊,實現(xiàn)代理:
- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
if(event.type==UIEventTypeRemoteControl){
switch (event.subtype) {
case UIEventSubtypeRemoteControlPlay:
[self.audioPlayer play];
break;
case UIEventSubtypeRemoteControlPause:
[self.audioPlayer pause];
break;
case UIEventSubtypeRemoteControlStop:
[self.audioPlayer stop];
break;
case UIEventSubtypeRemoteControlTogglePlayPause:
if (self.audioPlayer.isPlaying) {
[self.audioPlayer pause];
}else{
[self.audioPlayer play];
}
break;
case UIEventSubtypeRemoteControlNextTrack:
NSLog(@"Next...");
break;
case UIEventSubtypeRemoteControlPreviousTrack:
NSLog(@"Previous...");
break;
case UIEventSubtypeRemoteControlBeginSeekingForward:
NSLog(@"Begin seek forward...");
break;
case UIEventSubtypeRemoteControlEndSeekingForward:
NSLog(@"End seek forward...");
break;
case UIEventSubtypeRemoteControlBeginSeekingBackward:
NSLog(@"Begin seek backward...");
break;
case UIEventSubtypeRemoteControlEndSeekingBackward:
NSLog(@"End seek backward...");
break;
default:
break;
}
}
}
ViewController類實現(xiàn)如下:
//
// ViewController.m
// prac
//
// Created by Realank on 16/3/23.
// Copyright ? 2016年 realank. All rights reserved.
//
#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>
@interface ViewController () <AVAudioPlayerDelegate>
@property (nonatomic, strong) AVAudioPlayer *audioPlayer;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
if ([self.audioPlayer isPlaying]) {
[self.audioPlayer stop];
AVAudioSession *audioSession=[AVAudioSession sharedInstance];
[audioSession setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
}else{
[self musicPlayback];
}
}
- (AVAudioPlayer *)audioPlayer {
if (!_audioPlayer) {
NSString *urlStr=[[NSBundle mainBundle]pathForResource:@"liang.mp3" ofType:nil];
NSURL *url=[NSURL fileURLWithPath:urlStr];
NSError *error=nil;
//初始化播放器,注意這里的Url參數(shù)只能時文件路徑脸甘,不支持HTTP Url
_audioPlayer=[[AVAudioPlayer alloc]initWithContentsOfURL:url error:&error];
//設(shè)置播放器屬性
_audioPlayer.numberOfLoops=0;//設(shè)置為0不循環(huán)
_audioPlayer.delegate=self;
[_audioPlayer prepareToPlay];//加載音頻文件到緩存
if(error){
NSLog(@"初始化播放器過程發(fā)生錯誤,錯誤信息:%@",error.localizedDescription);
return nil;
}
AVAudioSession *audioSession=[AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
[audioSession setActive:YES error:nil];
//添加通知恳啥,拔出耳機后暫停播放
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(routeChange:) name:AVAudioSessionRouteChangeNotification object:nil];
}
return _audioPlayer;
}
- (void)musicPlayback {
if (!self.audioPlayer.isPlaying) {
[self.audioPlayer play];
}
}
-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
NSLog(@"音樂播放完成...");
}
/**
* 一旦輸出改變則執(zhí)行此方法
*
* @param notification 輸出改變通知對象
*/
-(void)routeChange:(NSNotification *)notification{
NSDictionary *dic=notification.userInfo;
int changeReason= [dic[AVAudioSessionRouteChangeReasonKey] intValue];
//等于AVAudioSessionRouteChangeReasonOldDeviceUnavailable表示舊輸出不可用
if (changeReason==AVAudioSessionRouteChangeReasonOldDeviceUnavailable) {
AVAudioSessionRouteDescription *routeDescription=dic[AVAudioSessionRouteChangePreviousRouteKey];
AVAudioSessionPortDescription *portDescription= [routeDescription.outputs firstObject];
//原設(shè)備為耳機則暫停
if ([portDescription.portType isEqualToString:@"Headphones"]) {
[self.audioPlayer pause];
}
}
}
-(void)dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVAudioSessionRouteChangeNotification object:nil];
}
- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
if(event.type==UIEventTypeRemoteControl){
switch (event.subtype) {
case UIEventSubtypeRemoteControlPlay:
[self.audioPlayer play];
break;
case UIEventSubtypeRemoteControlPause:
[self.audioPlayer pause];
break;
case UIEventSubtypeRemoteControlStop:
[self.audioPlayer stop];
break;
case UIEventSubtypeRemoteControlTogglePlayPause:
if (self.audioPlayer.isPlaying) {
[self.audioPlayer pause];
}else{
[self.audioPlayer play];
}
break;
case UIEventSubtypeRemoteControlNextTrack:
NSLog(@"Next...");
break;
case UIEventSubtypeRemoteControlPreviousTrack:
NSLog(@"Previous...");
break;
case UIEventSubtypeRemoteControlBeginSeekingForward:
NSLog(@"Begin seek forward...");
break;
case UIEventSubtypeRemoteControlEndSeekingForward:
NSLog(@"End seek forward...");
break;
case UIEventSubtypeRemoteControlBeginSeekingBackward:
NSLog(@"Begin seek backward...");
break;
case UIEventSubtypeRemoteControlEndSeekingBackward:
NSLog(@"End seek backward...");
break;
default:
break;
}
}
}
@end
AVAudioSession有必要進行一下詳細的說明:
在iOS中每個應用都有一個音頻會話,這個會話就通過AVAudioSession來表示丹诀。
AVAudioSession同樣存在于AVFoundation框架中钝的,它是單例模式設(shè)計,通過sharedInstance進行訪問铆遭。
在使用Apple設(shè)備時大家會發(fā)現(xiàn)有些應用只要打開其他音頻播放就會終止硝桩,而有些應用卻可以和其他應用同時播放,在多種音頻環(huán)境中如何去控制播放的方式就是通過音頻會話來完成的枚荣。
下面是音頻會話的幾種會話模式:
類似的碗脊,如果一個應用已經(jīng)在播放音頻,打開我們的應用之后設(shè)置了在后臺播放的會話類型棍弄,此時其他應用的音頻會停止而播放我們的音頻望薄,如果希望我們的程序音頻播放完之后(關(guān)閉或退出到后臺之后)能夠繼續(xù)播放其他應用的音頻的話則可以調(diào)用setActive::方法關(guān)閉會話:
AVAudioSession *audioSession=[AVAudioSession sharedInstance];
[audioSession setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
注意,setActive為NO的時候呼畸,一定要配上參數(shù)痕支,不然的話沒有什么卵用。
播放結(jié)束以后蛮原,setActive為NO是一個比較負責任的做法