iOS 4开始引入的multitask,咱们能够实现像ipod程序那样在后台播放音频了。若是音频操做是用苹果官方的AVFoundation.framework实现,像用AvAudioPlayer,AvPlayer播放的话,要实现完美的后台音频播放,依据app的功能须要,可能须要实现几个关键的功能。html
首先,播放音频以前先要设置AVAudioSession模式,一般只用来播放的App能够设为AVAudioSessionCategoryPlayback便可。模式意义及其余模式请参考文档。ios
//后台播放音频设置 AVAudioSession *session = [AVAudioSession sharedInstance]; [session setActive:YES error:nil]; [session setCategory:AVAudioSessionCategoryPlayback error:nil];
1.通知IOS该app支持background audio。缺省状况下,当按下home键时,当前正在运行的程序被suspend,状态从active变成in-active,也就是说若是正在播放音频,按下HOME后就会中止。这里须要让app在按在HOME后,转到后台运行而非被suspend,解决办法是在程序的-info.plist中增长required background modes这个key项,并选择App plays audio or streams audio/video using AirPlay这个value项(若是用过Xcode5.0,在TARGETS-Capabilities-Background Modes设置为ON,勾选Audio and AirPlay选项)。spring
2.若是你在后台播放使用的时加载网络音频,恰巧网速很慢,音频被中止下来这时候程序也随之suspend,曾经有山寨的解决办法是专门起一个player的实例连续不停的放同一无声音片段,阻止程序被suspend。这里提供的方法是经过申请后台taskID达到后台切换播放文件的功能。
即便声明taskID也最多只能在后台运行600秒钟。(在ios7sdk中可使用NSURLSession来实现后台缓冲)
(通常状况下,按HOME将程序送到后台,能够有5或10秒时间能够进行一些收尾工做,具体时间[[UIApplication sharedApplication] backgroundTimeRemaining]返回值,超时后app会被suspend。)api
3.ipod播放程序在后台时,双击HOME键,会有个控制界面,能够对它进行播放控制(暂停开始、上一曲、下一曲)。若是您想让您的app能够像ipod同样在后台也能够方便的经过双击HOME键来控制(在ios7中是使用上拉菜单控制),就要用到远程控制事件了。
首先在viewdidload等初始化的地方声明App接收远程控制事件,并在相应地方结束声明网络
- (void) viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [UIApplication sharedApplication] beginReceivingRemoteControlEvents]; [self becomeFirstResponder]; } - (void) viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [UIApplication sharedApplication] endReceivingRemoteControlEvents]; [self resignFirstResponder]; } - (BOOL)canBecomeFirstResponder { return YES; }
固然也不必定是在viewcontroller中,也能够是在applicationDidEnterBackground:方法中开始接受远程控制,applicationDidBecomeActive:中结束接受远程控制,可是当前的appdelegate中要继承与UIResponder,由于在激活远程控制之后要把当前类变成第一响应,重写canBecomeFirstResponder方法。session
最后定义 remoteControlReceivedWithEvent,处理具体的播放、暂停、前进、后退等具体事件app
//重写父类方法,接受外部事件的处理 - (void) remoteControlReceivedWithEvent: (UIEvent *) receivedEvent { if (receivedEvent.type == UIEventTypeRemoteControl) { switch (receivedEvent.subtype) { case UIEventSubtypeRemoteControlTogglePlayPause: [self playAndStopSong:self.playButton]; break; case UIEventSubtypeRemoteControlPreviousTrack: [self playLastButton:self.lastButton]; break; case UIEventSubtypeRemoteControlNextTrack: [self playNextSong:self.nextButton]; break; case UIEventSubtypeRemoteControlPlay: [self playAndStopSong:self.playButton]; break; case UIEventSubtypeRemoteControlPause: [self playAndStopSong:self.playButton]; break; default: break; } } }
其它外部事件也可经过这种方式实现,如“摇一摇”响应等。ide
4. 至此,您有播放App已经基本完成了,其次插拔耳机是否响应中止播放时间须要进一步研究耳机检测和声音路由切换的问题,再次不详细讲述。函数
5. 还有一些开发者可能会发现,有一些音视频app在定义的时候自定一些控件能够调节系统的音量大小,不须要用户调整音量按钮。经查看相关的资料总结出有两种方法:
一种是调用控件MPVolumeView在屏幕中建立一个音量条,拖动能够改变系统的音量大小。
另外一种是使用MPMusicPlayerController类,能够自定义控件调整系统音量的大小(可是在ios7sdk中已经被弃用,估计之后几个版本中可能找不到这个方法了)。ui
MPMusicPlayerController *mpc = [MPMusicPlayerController applicationMusicPlayer]; mpc.volume = 0; //0.0~1.0
6. 在一些其余的音乐播放软件中如:酷我、qq音乐等,你会发在播放的时候,当设备锁屏之后依然能够看到用户播放的音乐名称、演唱者、专辑名称、音乐时长、专辑图片等信息。这些就须要在用户切换完歌去的时候,在程序中设置信息了。
//设置锁屏状态,显示的歌曲信息 -(void)configNowPlayingInfoCenter{ if (NSClassFromString(@"MPNowPlayingInfoCenter")) { NSDictionary *info = [self.musicList objectAtIndex:_playIndex]; NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; //歌曲名称 [dict setObject:[info objectForKey:@"name"] forKey:MPMediaItemPropertyTitle]; //演唱者 [dict setObject:[info objectForKey:@"singer"] forKey:MPMediaItemPropertyArtist]; //专辑名 [dict setObject:[info objectForKey:@"album"] forKey:MPMediaItemPropertyAlbumTitle]; //专辑缩略图 UIImage *image = [UIImage imageNamed:[info objectForKey:@"image"]]; MPMediaItemArtwork *artwork = [[MPMediaItemArtwork alloc] initWithImage:image]; [dict setObject:artwork forKey:MPMediaItemPropertyArtwork]; //音乐剩余时长 [dict setObject:[NSNumber numberWithDouble:self.player.duration] forKey:MPMediaItemPropertyPlaybackDuration]; //音乐当前播放时间 在计时器中修改 //[dict setObject:[NSNumber numberWithDouble:0.0] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime]; //设置锁屏状态下屏幕显示播放音乐信息 [[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:dict]; } }
上面的if (NSClassFromString(@”MPNowPlayingInfoCenter”))语句,说是为了不了版本兼容问题,这个API貌似只出如今5里面。
7. 下面就在计时器中不断刷新锁屏状态下的播放进度条了。
//计时器修改进度 - (void)changeProgress:(NSTimer *)sender{ if(self.player){ //当前播放时间 NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:[[MPNowPlayingInfoCenter defaultCenter] nowPlayingInfo]]; [dict setObject:[NSNumber numberWithDouble:self.player.currentTime] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime]; //音乐当前已通过时间 [[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:dict]; } }
8. 当前的不少常见的播放器均可以在锁屏状态下显示显示歌词,通过一番查找后,终于找到方法(详情:点击查看),大体就是根据播放的时间和歌词显示时间,利用计时器不断的用歌词和专辑封面合成图片,达到显示歌词的效果。还有就是在屏幕变暗中止这一操做、屏幕点亮的时候开始计时器,以节省电量和cpu,有两种方法能够监听上述现象:
一种是监听内核层DarwinNotification,在Darwin中,有不少的系统事件,但apple的api文档描述这些api使用有限制,也就是灰色地带的api,因此能不用则不用;
另外一种方法能够经过notify_get_state来获取com.apple.springboard.hasBlankedScreen 的状态值,经过状态值咱们能够判断屏幕状态,屏幕亮或者暗系统会给出不一样状态值,而后根据状态值,经过NotificationCenter发送消息通知给相应的函数处理。