国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > iOS > 正文

iOS實現(xiàn)播放遠程網(wǎng)絡音樂的核心技術點總結(jié)

2019-10-21 18:50:56
字體:
供稿:網(wǎng)友

一、前言

這兩天做了個小項目涉及到了遠程音樂播放,因為第一次做這種音樂項目,邊查資料邊做,其中涉及到主要技術點有:

  • 如何播放遠程網(wǎng)絡音樂
  • 如何切換當前正在播放中的音樂資源
  • 如何監(jiān)聽音樂播放的各種狀態(tài)(播放器狀態(tài)、播放的進度、緩沖的進度,播放完成)
  • 如何手動操控播放進度
  • 如何在后臺模式或者鎖屏情況下正常播放音樂
  • 如何在鎖屏模式下顯示音樂播放信息和遠程操控音樂

如果您對一塊技術點有興趣或者正在尋找相關資料,那么本篇或許能提供一些參考或啟發(fā)。

二、 網(wǎng)絡音樂播放的核心技術點

根據(jù)自己的經(jīng)驗和查了一些音樂播放的相關資料,最簡單和最易上手的的技術方案我想應該是采用ios系統(tǒng)自帶的AVFoundation框架。

我們知道AVFoundation框架是蘋果專門為多媒體打造的一個庫,這個庫非常強大,專門用來處理音視頻等復雜的多媒體技術,而本篇要講的所有技術點就是基于AVFoundation框架中的一個類——AVPlayer。

那么AVPlayer是什么?

你可以把他看成是一個已經(jīng)封裝好的播放器,它的作用是用來播放遠程的或本地的視頻和音頻。因為本地的音視頻的播放比較簡單,這里就不做講述,本編主要是講遠程音樂播放,因為都是基于AVPlayer同一套API,所以掌握遠程音樂播放其實就是相當于掌握遠程視頻播放。好了廢話就不多說了,下面開始上菜。

1、導入AVFoundation框架,創(chuàng)建AVPlayer播放器

-(AVPlayer *)player{  if (_player == nil) {     // AVPlayerItem是一個包裝音樂資源的類,初始化時可以傳入一個音樂的url    AVPlayerItem *item = [[AVPlayerItem alloc] initWithURL:[NSURL URLWithString:@"http://xxxxxxxx"]];    //通過AVPlayerItem初始化player    _player = [[AVPlayer alloc] initWithPlayerItem:item];  }  return _player;}

此處懶加載創(chuàng)建,讓播放器成為控制器的全局屬性,注意需要強引用,否則回收釋放掉了就無法播放。

2、播放或停止音樂

  //開始播放  [self.player play];   //停止播放  [self.player pause];

這個沒什么好講的,只要調(diào)用AVPlayer的兩個實例方法

3、切換當前正在播放中的音樂資源

//創(chuàng)建需要播放的AVPlayerItem AVPlayerItem *item = [[AVPlayerItem alloc] initWithURL:[NSURL URLWithString:model.url]]; //替換當前音樂資源  [self.player replaceCurrentItemWithPlayerItem:item];

這個可以用于歌曲的切換,如上一首、下一首。

4、通過KVO監(jiān)聽播放器的狀態(tài)

 [self.player.currentItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];

拿到播放器的currentItem,注冊當前對象為觀察者,監(jiān)聽它的status屬性。status屬性是AVPlayerItemStatus類型,它是一個枚舉類型,如下:

typedef NS_ENUM(NSInteger, AVPlayerItemStatus) {  AVPlayerItemStatusUnknown,//未知狀態(tài)  AVPlayerItemStatusReadyToPlay,//準備播放  AVPlayerItemStatusFailed//加載失敗};

當status屬性值發(fā)生改變時,就會觸發(fā)觀察者方法的回調(diào),如下:

//觀察者回調(diào)-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{  //注意這里查看的是self.player.status屬性  if ([keyPath isEqualToString:@"status"]) {    switch (self.player.status) {      case AVPlayerStatusUnknown:      {        NSLog(@"未知轉(zhuǎn)態(tài)");      }        break;      case AVPlayerStatusReadyToPlay:      {        NSLog(@"準備播放");      }        break;      case AVPlayerStatusFailed:      {        NSLog(@"加載失敗");      }        break;         default:        break;    }  }}

self.player.status ==  AVPlayerStatusReadyToPlay時,音樂就會開始正常播放,另外兩種狀態(tài)音樂是無法播放的,可以在上面方法相應狀態(tài)里給出提示。這里需要特別強調(diào)一點的是觀察者監(jiān)聽的對象是 self.player.currentItem,而不是 self.player,而當監(jiān)聽的屬性發(fā)生改變時,觀察者回調(diào)的方法里需要查看的是 self.player.status。當然,你也可以不這么干,但是我嘗試過好幾次,不這么干的后果是無法監(jiān)聽到 self.player.status屬性的改變。

當音樂播放完成,或者切換下一首歌曲時,請務必記得移除觀察者,否則會crash。操作如下:

//移除觀察者 [self.player.currentItem removeObserver:self forKeyPath:@"status"];

5、監(jiān)聽音樂的緩沖進度

這個也是通過KVO監(jiān)聽播放器當前播放的音樂資源AVPlayerItem的loadedTimeRanges屬性。我們先看監(jiān)聽,如下:

//KVO監(jiān)聽音樂緩沖狀態(tài)[self.player.currentItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];

loadedTimeRanges屬性發(fā)生改變時,回調(diào)如下:

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{  if ([keyPath isEqualToString:@"loadedTimeRanges"]) {    NSArray * timeRanges = self.player.currentItem.loadedTimeRanges;    //本次緩沖的時間范圍    CMTimeRange timeRange = [timeRanges.firstObject CMTimeRangeValue];    //緩沖總長度    NSTimeInterval totalLoadTime = CMTimeGetSeconds(timeRange.start) + CMTimeGetSeconds(timeRange.duration);    //音樂的總時間    NSTimeInterval duration = CMTimeGetSeconds(self.player.currentItem.duration);    //計算緩沖百分比例    NSTimeInterval scale = totalLoadTime/duration;    //更新緩沖進度條    self.loadTimeProgress.progress = scale;  }}

loadedTimeRanges這個屬性是一個數(shù)組,里面裝的是本次緩沖的時間范圍,這個范圍是用一個結(jié)構(gòu)體 CMTimeRange表示,當然在oc中結(jié)構(gòu)體是不能直接存放數(shù)組的,所以它被包裝成了oc對象 NSValue

我們來看下這個結(jié)構(gòu)體:

typedef struct{  CMTime      start;      CMTime      duration;  } CMTimeRange;

start表示本次緩沖時間的起點,duratin表示本次緩沖持續(xù)的時間范圍,具體詳細的計算方法可以看上面方法的實現(xiàn)。

當音樂播放完成,或者切換下一首歌曲時,請務必記得移除觀察者,否則會crash。操作如下:

[self.player.currentItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];

6、監(jiān)聽音樂播放的進度

這個不是通過KVO了,AVPlayer專門提供了下面這個api用來監(jiān)聽播放的進度:

/** 監(jiān)聽音樂播放進度 @param interval 監(jiān)聽的時間間隔,用來設置多長時間回調(diào)一次 @param queue  隊列,一般傳主隊列 @param block  回調(diào)的block,會把當前的播放時間傳遞過來 @return 監(jiān)聽的對象 */- (id)addPeriodicTimeObserverForInterval:(CMTime)interval queue:(nullable dispatch_queue_t)queue usingBlock:(void (^)(CMTime time))block;

操作如下:

 __weak typeof(self) weakSelf = self;  self.timeObserver = [self.player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {    //當前播放的時間    float current = CMTimeGetSeconds(time);    //總時間    float total = CMTimeGetSeconds(item.duration);    if (current) {      float progress = current / total;      //更新播放進度條      weakSelf.playSlider.value = progress;      weakSelf.currentTime.text = [weakSelf timeFormatted:current];    }  }];

我們可以這個block里面拿到當前播放時間,根據(jù)總時間計算出當前播放所占的時間比例,最后更新播放進度條。這里又涉及到了一個數(shù)據(jù)類類型CMTime,它也是一個結(jié)構(gòu)體,用來作為時間的格式,定義如下:

  typedef struct   CMTimeValue  value;       CMTimeScale  timescale;     CMTimeFlags  flags;       CMTimeEpoch  epoch;      } CMTime;

CMTime是以分數(shù)的形式表示時間,value表示分子,timescale表示分母,flags是位掩碼,表示時間的指定狀態(tài)。所以我們要獲得時間的秒數(shù)需要分子除以分母。當然你還可以用下面這個函數(shù)來獲取時間的秒數(shù):

Float64 CMTimeGetSeconds(CMTime time)

最后,當音樂播放完成或者切換音樂時,依然需要移除監(jiān)聽:

if (self.timeObserver) {    [self.player removeTimeObserver:self.timeObserver];    self.timeObserver = nil;  }

7、手動超控(移動滑塊)播放進度

這是一個播放音視頻很常見的功能,所以強大的AVPlayer理所當然的提供了幾個api,下面只講述其中最簡單的一個:

/** 定位播放時間 @param time 指定的播放時間 */- (void)seekToTime:(CMTime)time;具體使用如下://移動滑塊調(diào)整播放進度- (IBAction)playSliderValueChange:(UISlider *)sender{  //根據(jù)值計算時間  float time = sender.value * CMTimeGetSeconds(self.player.currentItem.duration);  //跳轉(zhuǎn)到當前指定時間  [self.player seekToTime:CMTimeMake(time, 1)];}

8、監(jiān)聽音樂播放完成

一般音視頻播放完成時我們或多或少的都要處理一些業(yè)務,比如循環(huán)播放,播完退出界面等等。下面看下如何監(jiān)聽AVPlayer的播放完成。

//給AVPlayerItem添加播放完成通知  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:_player.currentItem];

這里是采用注冊監(jiān)聽AVPlayerItemDidPlayToEndTimeNotification通知,當AVPlayer一播放完成時,便會發(fā)出這個通知,我們收到通知后進行處理即可

9、設置音樂后臺播放

我們知道運行在ios系統(tǒng)下的程序一旦進入后臺就會處于休眠狀態(tài),程序停止運行了,也就播放不了什么音樂了。但是有一些特定功能的app還是處于可以后臺運行的,比如音樂類型的app正處于這個范疇。但是,并不是說你在應用中播放音樂就能后臺高枕無憂的運行了,你依然需要做如下幾步操作:

(1)開啟后臺模式

target ->capabilities-> Background modes ->打開開關 ->勾選第一個選項ios音樂播放器開發(fā),ios,音樂播放器代碼,ios網(wǎng)絡音樂播放器

(2)程序啟動時設置音頻會話

  //一般在方法:application: didFinishLaunchingWithOptions:設置  //獲取音頻會話  AVAudioSession *session = [AVAudioSession sharedInstance];  //設置類型是播放。  [session setCategory:AVAudioSessionCategoryPlayback error:nil];  //激活音頻會話。  [session setActive:YES error:nil];

以上兩步設置無誤,程序進入后臺模式,便可以進行音樂播放

10、如何設置音樂鎖頻信息

我們看百度音樂鎖頻時,也依然能在屏幕上展示歌曲的信息,以及切換歌曲等。下面看看這個功能是如何實現(xiàn)的:

//音樂鎖屏信息展示- (void)setupLockScreenInfo{  // 1.獲取鎖屏中心  MPNowPlayingInfoCenter *playingInfoCenter = [MPNowPlayingInfoCenter defaultCenter];  //初始化一個存放音樂信息的字典  NSMutableDictionary *playingInfoDict = [NSMutableDictionary dictionary];  // 2、設置歌曲名  if (self.currentModel.name) {    [playingInfoDict setObject:self.currentModel.name forKey:MPMediaItemPropertyAlbumTitle];  }  // 設置歌手名  if (self.currentModel.artist) {    [playingInfoDict setObject:self.currentModel.artist forKey:MPMediaItemPropertyArtist];  }  // 3設置封面的圖片  UIImage *image = [self getMusicImageWithMusicId:self.currentModel];  if (image) {    MPMediaItemArtwork *artwork = [[MPMediaItemArtwork alloc] initWithImage:image];    [playingInfoDict setObject:artwork forKey:MPMediaItemPropertyArtwork];  }  // 4設置歌曲的總時長  [playingInfoDict setObject:self.currentModel.detailDuration forKey:MPMediaItemPropertyPlaybackDuration];  //音樂信息賦值給獲取鎖屏中心的nowPlayingInfo屬性  playingInfoCenter.nowPlayingInfo = playingInfoDict;  // 5.開啟遠程交互,只有開啟這個才能進行遠程操控  [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];}

這里設置圖片時需要注意下,異步加載網(wǎng)絡圖片后再設置是無效的,所以圖片信息最好是先請求下來后再進行設置。

遠程超控的回調(diào)如下:

//監(jiān)聽遠程交互方法- (void)remoteControlReceivedWithEvent:(UIEvent *)event{  switch (event.subtype) {    //播放    case UIEventSubtypeRemoteControlPlay:{      [self.player play];          }      break;    //停止    case UIEventSubtypeRemoteControlPause:{      [self.player pause];          }      break;    //下一首    case UIEventSubtypeRemoteControlNextTrack:      [self nextBtnAction:nil];      break;    //上一首    case UIEventSubtypeRemoteControlPreviousTrack:      [self lastBtnAction:nil];      break;    default:      break;  }}

三、總結(jié)

最后,畫了一張圖總結(jié)下播放遠程網(wǎng)絡音樂的流程:ios音樂播放器開發(fā),ios,音樂播放器代碼,ios網(wǎng)絡音樂播放器

根據(jù)QQ音樂的界面做了個小demo,下面是demo的真機前臺和后臺播放的運行效果:ios音樂播放器開發(fā),ios,音樂播放器代碼,ios網(wǎng)絡音樂播放器

四、結(jié)束語

播放遠程網(wǎng)絡音樂的核心技術點基本上已經(jīng)寫完,當然AVPlayer還有很多強大的功能沒有寫出來,有興趣的可以進一步挖掘。寫到這里已經(jīng)疲倦至極,后續(xù)會持續(xù)更新一些精彩的技術點,也希望大家多多支持VEVB武林網(wǎng)。


注:相關教程知識閱讀請移步到IOS開發(fā)頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 瓮安县| 寿宁县| 绩溪县| 保定市| 光山县| 鄂尔多斯市| 永善县| 扬州市| 微山县| 军事| 松原市| 星子县| 于都县| 台前县| 东宁县| 闽清县| 昌江| 湟中县| 咸阳市| 墨竹工卡县| 盐山县| 丹巴县| 甘孜县| 乳源| 濮阳市| 宁强县| 万荣县| 桃园县| 师宗县| 手游| 长武县| 建水县| 贵阳市| 甘谷县| 玛沁县| 连州市| 昌吉市| 鄂伦春自治旗| 太仆寺旗| 汾西县| 高雄县|