AVPlayer播放網絡音樂
下載地址: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:
