天天看点

iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理

在没有网络的情况下,音频的后台播放比较简单,google一下可以搜到很多资料,但是如果每次歌曲的请求都是通过网络,就不成了,有时可以也扛不了几首,这里总结下实现方法,可以实现像电台一样的功能,后台播放,网络请求歌曲,remote控制,锁屏有封面,电话和听歌打断处理等。

iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理
iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理

音频播放器采用的avplayer ,自己进行了功能封装,暂且不谈,在程序启动的时候需要配置audiosession,audiosession负责应用音频的设置,比如支不支持后台,打断等等,这一步很重要,比如在viewdidload里初始化avplayer以后要调用下面的函数:

[objc] view plaincopy
iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理
iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理
-(void)setaudiosession{   //audiosessioninitialize用于控制打断 ,后面会说   audiosessioninitialize (   null,                          // ‘null’ to use the default (main) run loop   null,                          // ‘null’ to use the default run loop mode   asaudiosessioninterruptionlistener,  // a reference to your interruption callback   null                       // data to pass to your interruption listener callback   );   //这种方式后台,可以连续播放非网络请求歌曲,遇到网络请求歌曲就废,需要后台申请task   avaudiosession *session = [avaudiosession sharedinstance];   nserror *setcategoryerror = nil;   bool success = [session setcategory:avaudiosessioncategoryplayback error:&setcategoryerror];   if (!success)   {   /* handle the error condition */   return;   }   nserror *activationerror = nil;   success = [session setactive:yes error:&activationerror];  

audiosessioninitialize用于处理中断处理,avaudiosession主要调用setcategory和setactive方法来进行设置,avaudiosessioncategoryplayback一般用于支持后台播放,在官方文档可以看到其他的类型,每个分别适用于不同的场合:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

nsstring *const <a href="file:///users/lipengxuan/library/developer/shared/documentation/docsets/com.apple.adc.documentation.appleios6.0.ioslibrary.docset/contents/resources/documents/documentation/avfoundation/reference/avaudiosession_classreference/reference/reference.html#//apple_ref/doc/c_ref/avaudiosessioncategoryambient">

<blockquote>avaudiosessioncategoryambient</blockquote>

</a>;

nsstring *const <a href="file:///users/lipengxuan/library/developer/shared/documentation/docsets/com.apple.adc.documentation.appleios6.0.ioslibrary.docset/contents/resources/documents/documentation/avfoundation/reference/avaudiosession_classreference/reference/reference.html#//apple_ref/doc/c_ref/avaudiosessioncategorysoloambient">

<blockquote>avaudiosessioncategorysoloambient</blockquote>

nsstring *const <a href="file:///users/lipengxuan/library/developer/shared/documentation/docsets/com.apple.adc.documentation.appleios6.0.ioslibrary.docset/contents/resources/documents/documentation/avfoundation/reference/avaudiosession_classreference/reference/reference.html#//apple_ref/doc/c_ref/avaudiosessioncategoryplayback">

<blockquote>avaudiosessioncategoryplayback</blockquote>

nsstring *const <a href="file:///users/lipengxuan/library/developer/shared/documentation/docsets/com.apple.adc.documentation.appleios6.0.ioslibrary.docset/contents/resources/documents/documentation/avfoundation/reference/avaudiosession_classreference/reference/reference.html#//apple_ref/doc/c_ref/avaudiosessioncategoryrecord">

<blockquote>avaudiosessioncategoryrecord</blockquote>

nsstring *const <a href="file:///users/lipengxuan/library/developer/shared/documentation/docsets/com.apple.adc.documentation.appleios6.0.ioslibrary.docset/contents/resources/documents/documentation/avfoundation/reference/avaudiosession_classreference/reference/reference.html#//apple_ref/doc/c_ref/avaudiosessioncategoryplayandrecord">

<blockquote>avaudiosessioncategoryplayandrecord</blockquote>

nsstring *const <a href="file:///users/lipengxuan/library/developer/shared/documentation/docsets/com.apple.adc.documentation.appleios6.0.ioslibrary.docset/contents/resources/documents/documentation/avfoundation/reference/avaudiosession_classreference/reference/reference.html#//apple_ref/doc/c_ref/avaudiosessioncategoryaudioprocessing">

<blockquote>avaudiosessioncategoryaudioprocessing</blockquote>

nsstring *const <a href="file:///users/lipengxuan/library/developer/shared/documentation/docsets/com.apple.adc.documentation.appleios6.0.ioslibrary.docset/contents/resources/documents/documentation/avfoundation/reference/avaudiosession_classreference/reference/reference.html#//apple_ref/doc/c_ref/avaudiosessioncategorymultiroute">

<blockquote>avaudiosessioncategorymultiroute</blockquote>

除了代码的初始化,很重要的一步是对info-plist的设置,让应用支持音频的后台播放

iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理

库的引入包括:

audiotoolbox.framework

mediaplayer.framework

coremedia.framework

avfoundation.framework

正常情况下,如果配置了avaudiosessioncategoryplayback这个方法并修改了info-plist文件,应用就已经支持后台音频播放了,但是如果每一首歌曲都不存在本地,在网络的话就不行了,需要申请后台任务来进行处理,首先修改:

iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理
iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理
- (void)applicationdidenterbackground:(uiapplication *)application {   [application beginreceivingremotecontrolevents];  

然后在播放器的播放函数里添加:

iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理
iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理
-(void)justplay{   uibackgroundtaskidentifier bgtask = 0;   if([uiapplication sharedapplication].applicationstate== uiapplicationstatebackground) {   nslog(@”xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx后台播放”);   [theplayer play];   uiapplication*app = [uiapplication sharedapplication];   uibackgroundtaskidentifier newtask = [app beginbackgroundtaskwithexpirationhandler:nil];   if(bgtask!= uibackgroundtaskinvalid) {   [app endbackgroundtask: bgtask];   bgtask = newtask;   else {   nslog(@”xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx前台播放”);  

这样播放就可以进行前台或者后台的判断,支持网络后台播放了,一首一首连续播放。

在播放视图的viewcontroller里加上这两个函数:

iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理
iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理
- (void)viewdidappear:(bool)animated {   nslog(@”viewdidappear!!!”);   [super viewdidappear:animated];   //once the view has loaded then we can register to begin recieving controls and we can become the first responder   [[uiapplication sharedapplication] beginreceivingremotecontrolevents];   [self becomefirstresponder];   - (void)viewwilldisappear:(bool)animated {   nslog(@”viewwilldisappear!!!”);   [super viewwilldisappear:animated];   //end recieving events   [[uiapplication sharedapplication] endreceivingremotecontrolevents];   [self resignfirstresponder];  

当然也可以同理放到delegate.m里面的进入后台和回到前台的函数中,否则的话,上面的代码只是允许当前视图的情况下进入后台可以remote控制

然后添加下面的代码:

iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理
iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理
-(void)remotecontrolreceivedwithevent:(uievent *)event{   //if it is a remote control event handle it correctly   if (event.type == uieventtyperemotecontrol) {   if (event.subtype == uieventsubtyperemotecontroltoggleplaypause) {   [self playertap];   } else if (event.subtype == uieventsubtyperemotecontrolnexttrack){   [self nextsongauto];   [self confignowplayinginfocenter];   //make sure we can recieve remote control events   - (bool)canbecomefirstresponder {   return yes;  

一般在每次切换歌曲或者更新信息的时候要调用这个方法

iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理
iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理
- (void)confignowplayinginfocenter {   nsdictionary *albumdic=[currentparsersongarray objectatindex:songindex];   if (nsclassfromstring(@”mpnowplayinginfocenter”)) {   nsmutabledictionary * dict = [[nsmutabledictionary alloc] init];   [dict setobject:[albumdic objectforkey:@"name"] forkey:mpmediaitempropertytitle];   [dict setobject:[albumdic objectforkey:@"singer"] forkey:mpmediaitempropertyartist];   [dict setobject:[albumdic objectforkey:@"album"] forkey:mpmediaitempropertyalbumtitle];   mpmediaitemartwork * mart = [[mpmediaitemartwork alloc] initwithimage:cdcoverimgview.image];   [dict setobject:mart forkey:mpmediaitempropertyartwork];   [mpnowplayinginfocenter defaultcenter].nowplayinginfo = nil;   [[mpnowplayinginfocenter defaultcenter] setnowplayinginfo:dict];  

试用了官方文档上的各种代理方法,打断通知,都没用,后来用c函数处理可以控制打断,首先audiotoolbox.framework是需要引入的

在设定session的时候调用了asaudiosessioninterruptionlistener这个函数 ,就是处理打断的,在所需加入的类的实现

@implementation前面加入这个静态方法

iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理
iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理
static void asaudiosessioninterruptionlistener(voidvoid *inclientdata, uint32 ininterruptionstate)   [[toolmanager defaultmanager] handleinterruption:ininterruptionstate];  

每次打断结束或者开始都会调用这个方法  ,ininterruptionstate来判断是开始还是结束,因为是c函数,不可以直接调用类中[self  xxx]方法,通知也没用 ,故写了个单例类,接收这个参数,然后进行判断

iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理
iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理
- (void)handleinterruptionchangetostate:(nsnotification *)notification   audioqueuepropertyid ininterruptionstate=[[notification object] longvalue];   if (ininterruptionstate == kaudiosessionbegininterruption)   nslog(@”begin interruption——->”);   else if (ininterruptionstate == kaudiosessionendinterruption)   nslog(@”end interruption——->”);   }