// ViewController.h #import <UIKit/UIKit.h> #import <AVFoundation/AVFoundation.h> @class AVAudioPlayer; @interface PlayViewController : UIViewController<AVAudioPlayerDelegate> @property(nonatomic, strong) AVAudioPlayer *player; + (PlayViewController *)defaultPlayVC; //将该播放页面定义成单例 @end
// ViewController.m #import "PlayViewController.h" @interface PlayViewController () @property (retain, nonatomic) IBOutlet UIButton *suspendBtn; //暂停按钮 @property (retain, nonatomic) IBOutlet UIButton *formerBtn; //上一首按钮 @property (retain, nonatomic) IBOutlet UIButton *nextBtn; //下一首按钮 @property (retain, nonatomic) IBOutlet UISlider *slider; //滑块 @property (retain, nonatomic) NSArray *musicUrlArray; //音乐网址数组 @property (retain, nonatomic) NSArray *musicAllTimeArray; //音乐时间数组 @property (retain, nonatomic) NSTimer *timer; //计时器 @property (assign, nonatomic) int currentIndex; //当前音频下标 @end @implementation PlayViewController
#pragma mark 单例初始化方法 + (PlayViewController *)defaultPlayVC { static PlayViewController *playVC = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ playVC = [[PlayViewController alloc] init]; }); return playVC; } - (void)viewDidLoad { [super viewDidLoad]; self.currentIndex = 0; self.musicUrlArray = [NSArray arrayWithObjects:@"http://fdfs.xmcdn.com/group10/M08/D4/2E/wKgDaVZ9EYaQ-j48AFIOaAXL-wM019.mp3", @"http://fdfs.xmcdn.com/group13/M09/D4/17/wKgDXVZ6fR2wR1E8AFuO_VClRZA066.mp3", @"http://fdfs.xmcdn.com/group16/M0A/D5/16/wKgDbFZ89SqyFGWGAHoEKd7yPsw709.mp3", @"http://fdfs.xmcdn.com/group8/M01/D4/34/wKgDYFZ6y1nR6QpZAEDVy7rUTTc247.mp3", @"http://fdfs.xmcdn.com/group9/M00/D4/EF/wKgDZlZ7aLGCQEEDAHMsQsurq_Y170.mp3", @"http://fdfs.xmcdn.com/group12/M07/D4/C4/wKgDW1Z70rWxoDA7ABAp1lwS5nI990.mp3", nil]; self.musicAllTimeArray = [NSArray arrayWithObjects:@(1344.36), @(1500.04), @(1999.06), @(1062.22), @(1886.96), @(264.76), nil]; //滑块 self.slider.minimumValue = 0; [self.slider addTarget:self action:@selector(changValue:) forControlEvents:UIControlEventValueChanged]; //添加滑动事件 [self.slider setThumbImage:[UIImage imageNamed:@"playProcessDot_n"]forState:UIControlStateNormal]; //播放音频之前先要设置AVAudioSession模式 是它可以后台播放 //并且要在plist文件中 添加required background modes这个key项,并选择"App plays audio or streams audio/video using AirPlay"这个value项。 AVAudioSession *session = [AVAudioSession sharedInstance]; [session setCategory:AVAudioSessionCategoryPlayback error:nil]; [session setActive:YES error:nil]; [self playerCurrentMusic]; } -(void)playerCurrentMusic { //创建串行队列 (放入线程中,免得页面假死) dispatch_queue_t serialQueue = dispatch_queue_create("com.audio.www", DISPATCH_QUEUE_SERIAL); dispatch_async(serialQueue, ^{ NSString *url = self.musicUrlArray[self.currentIndex]; NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]]; self.player = [[AVAudioPlayer alloc] initWithData:data error:nil]; self.player.delegate = self; [self.player prepareToPlay]; [self.player play]; //滑块 CGFloat allTime = [self.musicAllTimeArray[self.currentIndex] floatValue]; self.slider.maximumValue = allTime; //计时器只能在主线程中 dispatch_async(dispatch_get_main_queue(), ^{ self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(reloadAction) userInfo:nil repeats:YES]; }); }); } #pragma mark -- 每1秒 给进度条赋一次值 -(void)reloadAction { if ([self.player isPlaying]) { self.slider.value = self.player.currentTime; } } #pragma mark 点击暂停 - (IBAction)suspendAction:(UIButton *)sender { sender.selected = !sender.selected; if (sender.selected) { [self.player pause]; //暂停 [sender setTitle:@"播放" forState:UIControlStateSelected]; } else { [self.player play]; //播放 [sender setTitle:@"暂停" forState:UIControlStateNormal]; } } #pragma mark 点击上一首 - (IBAction)formerAction:(UIButton *)sender { [self myPlayFormer]; //播放上一首 } #pragma mark 点击下一首 - (IBAction)nextAction:(UIButton *)sender { [self myPlayNext]; //播放下一首 } #pragma mark 上一首 -(void)myPlayFormer { if (self.currentIndex > 0) { [self.player pause]; self.currentIndex--; [self playerCurrentMusic]; } } #pragma mark 下一首 -(void)myPlayNext { if (self.currentIndex < self.musicUrlArray.count - 1) { [self.player pause]; self.currentIndex++; [self playerCurrentMusic]; } } /***************** 控制台 *****************/ #pragma mark -- 声明App接收远程控制事件 -(void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; [self becomeFirstResponder]; } #pragma mark -- App结束声明接收远程控制事件 - (void) viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [[UIApplication sharedApplication] endReceivingRemoteControlEvents]; [self resignFirstResponder]; } #pragma mark -- 接受控制台的控制事件 - (void)remoteControlReceivedWithEvent: (UIEvent *) receivedEvent { if (receivedEvent.type == UIEventTypeRemoteControl) { //判断点击按钮的类型 switch (receivedEvent.subtype) { case UIEventSubtypeRemoteControlPlay: [self.player play]; //播放 break; case UIEventSubtypeRemoteControlPause: [self.player pause]; //暂停 break; case UIEventSubtypeRemoteControlPreviousTrack: [self myPlayFormer]; //播放上一首 break; case UIEventSubtypeRemoteControlNextTrack: [self myPlayNext]; //播放下一首 break; default: break; } } } #pragma mark 实现后台播放完一首后, 继续播放下一首 - (BOOL)canBecomeFirstResponder { return YES; } /***************** AVAudioPlayer 代理 *****************/ #pragma mark -- 后台播放被打断, 继续恢复播放 (比如打电话...) - (void)audioPlayerEndInterruption:(AVAudioPlayer *)player withOptions:(NSUInteger)flags { [self.player play]; } #pragma mark -- 播放完当前声音后,播放下一首 -(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag { if (self.currentIndex < self.musicUrlArray.count - 1) { self.currentIndex++; [self playerCurrentMusic]; } } #pragma mark -- 滑块滑动改变播放进度(代理方法) -(void)changValue:(UISlider *)slider { //拖动滑块时, 停止计时器 [self.timer invalidate]; self.player.currentTime = slider.value; //开始计时器 self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(reloadAction) userInfo:nil repeats:YES]; }
想要实现后台播放(即程序进入后台,音乐继续播放)需要修改plist文件:
1.添加required background modes这个key项,并选择"App plays audio or streams audio/video using AirPlay"这个value项。
需要在后台实现播放页的各种上一首,下一首...各种功能, 还需要在Appdelegate.m的background方法里:
- (void)applicationDidEnterBackground:(UIApplication *)application { //程序进入后台后, 为了让音乐继续播放, 在此方法里创建该代理播放页, 并指定它播放器的代理 PlayViewController *player = [PlayViewController defaultPlayVC]; player.player.delegate = player; }