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: