AVAudioPlayer播放並實現了後臺播放和遠端控制
阿新 • • 發佈:2019-02-06
// 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項。
2.XCode7.1以上獲取網路資料,需要修改plist檔案
在Info.plist中新增App
Transport Security Settings型別Dictionary。
在App Transport Security Settings下新增Allow
Arbitrary Loads型別Boolean,值設為YES
需要在後臺實現播放頁的各種上一首,下一首...各種功能, 還需要在Appdelegate.m的background方法裡:
- (void)applicationDidEnterBackground:(UIApplication *)application {
//程式進入後臺後, 為了讓音樂繼續播放, 在此方法裡建立該代理播放頁, 並指定它播放器的代理
PlayViewController *player = [PlayViewController defaultPlayVC];
player.player.delegate = player;
}
當前工程Demo地址: http://download.csdn.net/detail/margaret_mo/9412069