AVPlayer播放網絡音樂


AVPlayer播放網絡音樂

144 
作者 Wy_chris 
2016.09.23 17:23* 字數 411 閱讀 355評論 6

下載地址:AVPlayer播放網絡音樂

音樂播放並展示到界面上需要我們實現的功能如下:

1、(核心)播放器通過一個網絡鏈接播放音樂
2、(基本)播放器的常用操作:暫停、播放、上一首、下一首等等
3、(基本)監聽該音樂的播放進度、獲取音樂的總時間、當前播放時間
4、(基本)監聽改播放器狀態:
     (1)媒體加載狀態
     (2)數據緩沖狀態
     (3)播放完畢狀態
5、(可選)Remote Control控制音樂的播放
6、(可選)Now Playing Center展示正在播放的音樂

功能實現

我自己寫了一個管理類 (里面封裝了大部分播放邏輯)
已完成功能:播放、暫停、上下一首、單曲循環、隨機播放、后台播放、鎖屏信息。
第一次寫這種管理類,可能會有點復雜,不太容易看懂 。 我把歌曲的信息也存在里面了。

.h 文件

#import <Foundation/Foundation.h> #import <AVFoundation/AVFoundation.h> #import "SongsMessageModel.h" typedef NS_ENUM(NSInteger, playerType) { AVPlayerTypeNormal = 0, //正常循環播放狀態 AVPlayerTypeRandom, //隨機播放 AVPlayerTypeSingle, //單曲循環 }; /**返回緩沖進度*/ typedef void(^loadTime)(NSString *str); /**返回 當前進度、總時長、slider 最大值和當前值*/ typedef void(^returnTime)(NSString *current,NSString *total,float max,float value); /**返回 AVPlayerItem的序號(換背景圖、歌手、歌曲)*/ typedef void(^returnImage)(NSInteger index); @interface AVPlayerManager : NSObject /**存放AVplayerItem的數組*/ @property(nonatomic,strong)NSMutableArray *musicArray; //**歌曲地址數組*/ @property(nonatomic,strong)NSMutableArray *songArray;// 是否進入的已存在的歌單! /**海報數組*/ @property(nonatomic,strong)NSMutableArray *imageArray; /**歌手數組*/ @property(nonatomic,strong)NSMutableArray *singerArray; /**歌曲名數組*/ @property(nonatomic,strong)NSMutableArray *songNameArray; /**AVPlayer播放器*/ @property (nonatomic, strong) AVPlayer *player; /**播放模式*/ @property (nonatomic,assign) NSInteger playerType; /**當前播放時間*/ @property(nonatomic,assign) float currentPlayTime; /**當前緩沖時間*/ @property(nonatomic,assign)NSTimeInterval currentLoadTime; /**slider最大值*/ @property(nonatomic,assign) float silderMaxValue; /**slider當前值*/ @property(nonatomic,assign) float silderValue; /***/ @property(nonatomic,strong) NSString *playTime; /**總時長*/ @property(nonatomic,strong) NSString *totalTime; /**緩沖提示*/ @property(nonatomic,strong) NSString *loadTime; @property(nonatomic,strong)loadTime block; @property(nonatomic,strong)returnTime block1; @property(nonatomic,strong) returnImage block2; /**通知 獲取當前播放狀態 控制按鈕狀態*/ @property(nonatomic,strong) NSNotificationCenter * center; /**判斷是否是從歌單列表進入播放器 還是 直接在進入播放器*/ @property(nonatomic,assign) BOOL listInto; + (instancetype)shareManager; //**播放*/ - (void)musicPlayerWithArray:(NSArray *)musicArray andIndex:(NSInteger )index; //**正在播放時 播放指定歌曲, */ - (void)musicPlayerWithIndex:(NSInteger )index; //*播放 -(void)playMusic; //*暫停 -(void)pasueMusic; //**下一首*/ - (void)nextSong; //**上一首*/ - (void)lastSong; //**進度條 調節 */ - (void)playerProgressWithProgressFloat:(CGFloat)progressFloat; //**移除觀察者*/ -(void)removeObserver; /**獲取當前播放序號*/ -(NSInteger )getcurrentItem;

.m 文件

#import "AVPlayerManager.h" #import <MediaPlayer/MediaPlayer.h> @implementation AVPlayerManager { id timeObserve;// 為 當前AVPlayerItem 添加觀察者獲取各種播放狀態 } +(instancetype)shareManager{ static AVPlayerManager *manager = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ manager = [AVPlayerManager new]; }); return manager; } -(instancetype)init{ if (self =[super init]) { _playerType = AVPlayerTypeNormal; } return self; } //播放器懶加載 -(AVPlayer *)player{ if (!_player) { _player = [AVPlayer new]; } return _player; } -(NSMutableArray *)musicArray{ if (!_musicArray) { _musicArray = [NSMutableArray array]; _center = [NSNotificationCenter defaultCenter]; } return _musicArray; } //播放指定url - (void)musicPlayerWithURL:(NSURL *)playerItemURL{ //創建要播放的資源 AVPlayerItem *playerItem = [[AVPlayerItem alloc]initWithURL:playerItemURL]; //添加觀察者 //播放當前資源 [self.player replaceCurrentItemWithPlayerItem:playerItem]; } -(void)musicPlayerWithIndex:(NSInteger)index{ // 播放AVPlayerItem數組中指定序號歌曲 (此操作之前需要將上一個item 的 觀察者移除 並將 seekTime 設置為0 確保下次播放從頭開始) [self.player replaceCurrentItemWithPlayerItem:self.musicArray[index]]; self.block2([self.musicArray indexOfObject:self.player.currentItem]); [self addObserver]; } //重新添加新的歌單列表進來 - (void)musicPlayerWithArray:(NSArray *)musicArray andIndex:(NSInteger )index{ //首先移除之前的歌單列表 再 重新添加 [self.songArray removeAllObjects]; [self.songArray addObjectsFromArray:musicArray]; for (NSString * obj in musicArray) { AVPlayerItem *songItem = [[AVPlayerItem alloc] initWithURL:[NSURL URLWithString:obj]]; [self.musicArray addObject:songItem]; } //播放歌單列表序號對應的歌曲 [self.player replaceCurrentItemWithPlayerItem:self.musicArray[index]]; //對當前item 添加觀察者 [self addObserver]; } //播放 -(void)playMusic{ [self.player play]; } //暫停 -(void)pasueMusic{ [self.player pause]; } //上一首 -(void)lastSong{ [self removeObserver];//先移除當前 觀察者 [self.player.currentItem seekToTime:(kCMTimeZero) completionHandler:^(BOOL finished) { if (self.playerType == AVPlayerTypeNormal) {//順序循環播放 //判斷當前歌曲是否是第一首歌曲,如果是跳轉到最后一首歌 if ([self.musicArray indexOfObject:self.player.currentItem] ==0) { [self.player replaceCurrentItemWithPlayerItem:self.musicArray.lastObject]; }else{ [self.player replaceCurrentItemWithPlayerItem:self.musicArray[[self.musicArray indexOfObject:self.player.currentItem]-1]]; } }else if (self.playerType == AVPlayerTypeRandom){//隨機播放 NSInteger random = arc4random_uniform((int)self.musicArray.count); NSLog(@"%ld",random); [self.player replaceCurrentItemWithPlayerItem:self.musicArray[arc4random_uniform((int)self.musicArray.count)]]; }else if (self.playerType ==AVPlayerTypeSingle){ //單曲循環在自動切換歌曲時進行判斷 //判斷當前歌曲是否是第一首歌曲,如果是跳轉到最后一首歌 if ([self.musicArray indexOfObject:self.player.currentItem] ==0) { [self.player replaceCurrentItemWithPlayerItem:self.musicArray.lastObject]; }else{ [self.player replaceCurrentItemWithPlayerItem:self.musicArray[[self.musicArray indexOfObject:self.player.currentItem]-1]]; } } [self playMusic]; //放回對應歌曲的信息 self.block2([self.musicArray indexOfObject:self.player.currentItem]); [self addObserver];//添加觀察者 }]; } //下一首 -(void)nextSong{ [self removeObserver]; [self.player.currentItem seekToTime:(kCMTimeZero) completionHandler:^(BOOL finished) { if (self.playerType == AVPlayerTypeNormal) { //判斷當前歌曲是否是最后一首歌曲,如果是跳轉到第一首歌 if ([self.musicArray indexOfObject:self.player.currentItem]+1 == self.musicArray.count) { [self.player replaceCurrentItemWithPlayerItem:self.musicArray.firstObject]; }else{ [self.player replaceCurrentItemWithPlayerItem:self.musicArray[[self.musicArray indexOfObject:self.player.currentItem]+1]]; } }else if (self.playerType == AVPlayerTypeRandom){ [self.player replaceCurrentItemWithPlayerItem:self.musicArray[arc4random_uniform((int)self.musicArray.count)]]; }else if (self.playerType == AVPlayerTypeSingle){ //判斷當前歌曲是否是最后一首歌曲,如果是跳轉到第一首歌 if ([self.musicArray indexOfObject:self.player.currentItem]+1 == self.musicArray.count) { [self.player replaceCurrentItemWithPlayerItem:self.musicArray.firstObject]; }else{ [self.player replaceCurrentItemWithPlayerItem:self.musicArray[[self.musicArray indexOfObject:self.player.currentItem]+1]]; } } [self playMusic]; self.block2([self.musicArray indexOfObject:self.player.currentItem]); [self addObserver]; }]; } //獲取 當前播放歌曲在AVPlayerItem中的 序號 -(NSInteger )getcurrentItem{ return [self.musicArray indexOfObject:self.player.currentItem]; } //將slider的值傳入使 歌曲進度 前進或后退 -(void)playerProgressWithProgressFloat:(CGFloat)progressFloat{ if (progressFloat > self.currentLoadTime) { NSDictionary *dict = @{@"播放狀態":@0}; [self.center postNotificationName:@"playOrPasue" object:self userInfo:dict]; } [self.player seekToTime:CMTimeMake(progressFloat, 1.0)]; } //接受播放完成的通知 開始下一首 - (void)playbackFinished:(NSNotification *)notice { //判斷是否是單曲循環 是的話 移除觀察者 將當前進度調為0 重新播放 if (self.playerType == AVPlayerTypeSingle) { [self removeObserver]; [self.player.currentItem seekToTime:kCMTimeZero]; [self musicPlayerWithIndex:[self getcurrentItem]]; [self playMusic]; }else{ [self nextSong]; } } //為當前播放的item 添加觀察者 -(void)addObserver{ __weak typeof(self) weekSelf = self; __weak AVPlayer *weekPlayer = self.player; //觀察該item 是否能播放 [self.player.currentItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil]; //觀察該item 加載進度 [self.player.currentItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil]; //AVPlayer 自帶方法:返回歌曲 播放進度 信息 timeObserve = [self.player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) { [weekSelf updateLockedScreenMusic:[weekSelf getcurrentItem]]; float current = CMTimeGetSeconds(time); float total = CMTimeGetSeconds(weekPlayer.currentItem.duration); weekSelf.currentPlayTime = current; if (total > 0) { weekSelf.silderMaxValue = total; }else{ weekSelf.silderMaxValue = 300; }; weekSelf.silderValue = current; if (current) { weekSelf.playTime =[weekSelf timetranstation:[NSString stringWithFormat:@"%.f",current]]; weekSelf.totalTime =[weekSelf timetranstation:[NSString stringWithFormat:@"%.f",total]]; //判斷歌曲播完 后發出通知 -132行 接受通知 if (current == total) { // total - current <=1 有時會導致不能正常切換歌曲 [[NSNotificationCenter defaultCenter] addObserver:weekSelf selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:weekPlayer.currentItem]; } //返回 播放界面所需要的內容。 weekSelf.block1(weekSelf.playTime,weekSelf.totalTime,weekSelf.silderMaxValue,weekSelf.silderValue); } }]; } //移除對當前item 的觀察 通知 -(void)removeObserver{ if (timeObserve) { [[NSNotificationCenter defaultCenter] removeObserver:self]; [self.player.currentItem removeObserver:self forKeyPath:@"loadedTimeRanges"]; [self.player.currentItem removeObserver:self forKeyPath:@"status"]; [self.player removeTimeObserver:timeObserve]; } } //觀察者 -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ AVPlayerItem * songItem = object; NSDictionary *dict = @{@"播放狀態":@1}; if ([keyPath isEqualToString:@"status"]) { switch (self.player.status) { case AVPlayerStatusUnknown: // BASE_INFO_FUN(@"KVO:未知狀態,此時不能播放"); break; case AVPlayerStatusReadyToPlay: // self.status = SUPlayStatusReadyToPlay; // BASE_INFO_FUN(@"KVO:准備完畢,可以播放"); [self.center postNotificationName:@"playOrPasue" object:self userInfo:dict]; [self.player play]; break; case AVPlayerStatusFailed: // BASE_INFO_FUN(@"KVO:加載失敗,網絡或者服務器出現問題"); break; default: break; } }else if ([keyPath isEqualToString:@"loadedTimeRanges"]) { NSArray * array = songItem.loadedTimeRanges; CMTimeRange timeRange = [array.firstObject CMTimeRangeValue]; //本次緩沖的時間范圍 NSTimeInterval totalBuffer = CMTimeGetSeconds(timeRange.start) + CMTimeGetSeconds(timeRange.duration); //緩沖總長度 self.currentLoadTime = totalBuffer; float total = CMTimeGetSeconds(songItem.duration); // NSLog(@"共緩沖%.0f%",totalBuffer/total*100); 計算緩沖進度 self.loadTime =[NSString stringWithFormat:@"正在緩沖%.0f%",totalBuffer/total*100]; if ([[NSString stringWithFormat:@"%.0f",totalBuffer/total*100] isEqualToString:@"100"]) { self.loadTime =@""; }else{ self.loadTime =[NSString stringWithFormat:@"正在緩沖%.0f%",totalBuffer/total*100]; } CGFloat currentPlayTime = self.currentPlayTime; //緩沖完成時間大於當前播放時間5s時通知播放器繼續播放 否則暫停 if (totalBuffer > currentPlayTime +5) { // NSDictionary *dict = @{@"播放狀態":@1}; // [self.center postNotificationName:@"playOrPasue" object:self userInfo:dict]; }else{ NSDictionary *dict = @{@"播放狀態":@0}; [self.center postNotificationName:@"playOrPasue" object:self userInfo:dict]; } NSLog(@"%f ----%f",total,totalBuffer); if (totalBuffer + 1 > total) { NSDictionary *dict = @{@"播放狀態":@1}; [self.center postNotificationName:@"playOrPasue" object:self userInfo:dict]; } self.block(self.loadTime); } } #pragma 秒數轉為分鍾 -(NSString *)timetranstation:(NSString *)time{ NSString *returnTime =[NSString string]; NSInteger total = [time integerValue]; returnTime =[NSString stringWithFormat:@"%02ld:%02ld",total/60,total%60]; return returnTime; } #pragma mark - 鎖屏時候的設置,效果需要在真機上才可以看到 - (void)updateLockedScreenMusic:(NSInteger )index{ // 播放信息中心 MPNowPlayingInfoCenter *center = [MPNowPlayingInfoCenter defaultCenter]; // 初始化播放信息 NSMutableDictionary *info = [NSMutableDictionary dictionary]; // 專輯名稱 // info[MPMediaItemPropertyAlbumTitle] = [sel]; // 歌手 info[MPMediaItemPropertyArtist] = self.singerArray[index]; // 歌曲名稱 info[MPMediaItemPropertyTitle] = self.songNameArray[index]; // 設置圖片 info[MPMediaItemPropertyArtwork] = [[MPMediaItemArtwork alloc] initWithImage:[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@",self.imageArray[index]]]]]]; // 設置持續時間(歌曲的總時間) [info setObject:[NSNumber numberWithFloat:CMTimeGetSeconds([self.player.currentItem duration])] forKey:MPMediaItemPropertyPlaybackDuration]; // 設置當前播放進度 [info setObject:[NSNumber numberWithFloat:CMTimeGetSeconds([self.player.currentItem currentTime])] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime]; // 切換播放信息 center.nowPlayingInfo = info; }

第一次寫,如果哪位大神耐心看了,希望多給一點指點,不足的地方指出來。我要多學習學習!!!

demo中的網絡地址來自於 阿里星球 , 因為是在線播放,所以在真機上面跑會有點卡 ,希望大神指點!需要怎么處理?

參考鏈接:iOS音頻篇:使用AVPlayer播放網絡音樂


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM