在没有网络的情况下,音频的后台播放比较简单,google一下可以搜到很多资料,但是如果每次歌曲的请求都是通过网络,就不成了,有时可以也扛不了几首,这里总结下实现方法,可以实现像电台一样的功能,后台播放,网络请求歌曲,remote控制,锁屏有封面,电话和听歌打断处理等。
音频播放器采用的avplayer ,自己进行了功能封装,暂且不谈,在程序启动的时候需要配置audiosession,audiosession负责应用音频的设置,比如支不支持后台,打断等等,这一步很重要,比如在viewdidload里初始化avplayer以后要调用下面的函数:
[objc] view plaincopy![]()
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];![]()
iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理
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的设置,让应用支持音频的后台播放
库的引入包括:
audiotoolbox.framework
mediaplayer.framework
coremedia.framework
avfoundation.framework
正常情况下,如果配置了avaudiosessioncategoryplayback这个方法并修改了info-plist文件,应用就已经支持后台音频播放了,但是如果每一首歌曲都不存在本地,在网络的话就不行了,需要申请后台任务来进行处理,首先修改:
![]()
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前台播放”);![]()
iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理
这样播放就可以进行前台或者后台的判断,支持网络后台播放了,一首一首连续播放。
在播放视图的viewcontroller里加上这两个函数:
![]()
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];![]()
iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理
当然也可以同理放到delegate.m里面的进入后台和回到前台的函数中,否则的话,上面的代码只是允许当前视图的情况下进入后台可以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];![]()
iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理
试用了官方文档上的各种代理方法,打断通知,都没用,后来用c函数处理可以控制打断,首先audiotoolbox.framework是需要引入的
在设定session的时候调用了asaudiosessioninterruptionlistener这个函数 ,就是处理打断的,在所需加入的类的实现
@implementation前面加入这个静态方法
![]()
iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理 static void asaudiosessioninterruptionlistener(voidvoid *inclientdata, uint32 ininterruptionstate) [[toolmanager defaultmanager] handleinterruption:ininterruptionstate];![]()
iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理
每次打断结束或者开始都会调用这个方法 ,ininterruptionstate来判断是开始还是结束,因为是c函数,不可以直接调用类中[self xxx]方法,通知也没用 ,故写了个单例类,接收这个参数,然后进行判断
![]()
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——->”); }![]()
iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断) 初始化AudioSession和基本配置 后台播放 Remote控制 锁屏封面 打断处理