你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS完成播放近程網絡音樂的中心技術點總結

iOS完成播放近程網絡音樂的中心技術點總結

編輯:IOS開發綜合

一、前言

這兩天做了個小項目觸及到了近程音樂播放,由於第一次做這種音樂項目,邊查材料邊做,其中觸及到次要技術點有:

如何播放近程網絡音樂 如何切換以後正在播放中的音樂資源 如何監聽音樂播放的各種形態(播放器形態、播放的進度、緩沖的進度,播放完成) 如何手動操控播放進度 如何在後台形式或許鎖屏狀況下正常播放音樂 如何在鎖屏形式下顯示音樂播放信息和近程操控音樂

假如您對一塊技術點有興味或許正在尋覓相關材料,那麼本篇或許能提供一些參考或啟示。

二、 網絡音樂播放的中心技術點

依據自己的經歷和查了一些音樂播放的相關材料,最復雜和最易上手的的技術方案我想應該是采用IOS零碎自帶的AVFoundation框架。

我們知道AVFoundation框架是蘋果專門為多媒體打造的一個庫,這個庫十分弱小,專門用來處置音視頻等復雜的多媒體技術,而本篇要講的一切技術點就是基於AVFoundation框架中的一個類——AVPlayer。

那麼AVPlayer是什麼?

你可以把他看成是一個曾經封裝好的播放器,它的作用是用來播放近程的或本地的視頻和音頻。由於本地的音視頻的播放比擬復雜,這裡就不做講述,本編次要是講近程音樂播放,由於都是基於AVPlayer同一套API,所以掌握近程音樂播放其實就是相當於掌握近程視頻播放。好了廢話就不多說了,上面開端上菜。

1、導入AVFoundation框架,創立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;
}

此處懶加載創立,讓播放器成為控制器的全局屬性,留意需求強援用,否則回收釋放掉了就無法播放。

2、播放或中止音樂

  //開端播放
  [self.player play];
   //中止播放
  [self.player pause];

這個沒什麼好講的,只需調用AVPlayer的兩個實例辦法

3、切換以後正在播放中的音樂資源

//創立需求播放的AVPlayerItem
 AVPlayerItem *item = [[AVPlayerItem alloc] initWithURL:[NSURL URLWithString:model.url]];
 //交換以後音樂資源 
 [self.player replaceCurrentItemWithPlayerItem:item];

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

4、經過KVO監聽播放器的形態

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

拿到播放器的currentItem,注冊以後對象為察看者,監聽它的status屬性。status屬性是AVPlayerItemStatus類型,它是一個枚舉類型,如下:

typedef NS_ENUM(NSInteger, AVPlayerItemStatus) {
  AVPlayerItemStatusUnknown,//未知形態
  AVPlayerItemStatusReadyToPlay,//預備播放
  AVPlayerItemStatusFailed//加載失敗
};

當status屬性值發作改動時,就會觸發察看者辦法的回調,如下:

//察看者回調
-(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(@"未知轉態");
      }
        break;
      case AVPlayerStatusReadyToPlay:
      {
        NSLog(@"預備播放");
      }
        break;
      case AVPlayerStatusFailed:
      {
        NSLog(@"加載失敗");
      }
        break;
         default:
        break;
    }
  }
}

self.player.status ==  AVPlayerStatusReadyToPlay時,音樂就會開端正常播放,另外兩種形態音樂是無法播放的,可以在下面辦法相應形態裡給出提示。這裡需求特別強調一點的是察看者監聽的對象是 self.player.currentItem,而不是 self.player,而當監聽的屬性發作改動時,察看者回調的辦法裡需求檢查的是 self.player.status。當然,你也可以不這麼干,但是我嘗試過好幾次,不這麼干的結果是無法監聽到 self.player.status屬性的改動。

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

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

5、監聽音樂的緩沖進度

這個也是經過KVO監聽播放器以後播放的音樂資源AVPlayerItem的loadedTimeRanges屬性。我們先看監聽,如下:

//KVO監聽音樂緩沖形態
[self.player.currentItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];

loadedTimeRanges屬性發作改動時,回調如下:

-(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這個屬性是一個數組,外面裝的是本次緩沖的時間范圍,這個范圍是用一個構造體 CMTimeRange表示,當然在oc中構造體是不能直接寄存數組的,所以它被包裝成了oc對象 NSValue

我們來看下這個構造體:

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

start表示本次緩沖時間的終點,duratin表示本次緩沖繼續的時間范圍,詳細詳細的計算辦法可以看下面辦法的完成。

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

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

6、監聽音樂播放的進度

這個不是經過KVO了,AVPlayer專門提供了上面這個api用來監聽播放的進度:

/**
 監聽音樂播放進度

 @param interval 監聽的時間距離,用來設置多長時間回調一次
 @param queue  隊列,普通傳客隊列
 @param block  回調的block,會把以後的播放時間傳遞過去

 @return 監聽的對象
 */
- (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外面拿到以後播放時間,依據總時間計算出以後播放所占的時間比例,最後更新播放進度條。這裡又觸及到了一個數據類類型CMTime,它也是一個構造體,用來作為時間的格式,定義如下:

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

CMTime是以分數的方式表示時間,value表示分子,timescale表示分母,flags是位掩碼,表示時間的指定形態。所以我們要取得時間的秒數需求分子除以分母。當然你還可以用上面這個函數來獲取時間的秒數:

Float64 CMTimeGetSeconds(CMTime time)

最後,當音樂播放完成或許切換音樂時,仍然需求移除監聽:

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

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

這是一個播放音視頻很罕見的功用,所以弱小的AVPlayer天經地義的提供了幾個api,上面只講述其中最復雜的一個:

/**
 定位播放時間

 @param time 指定的播放時間
 */
- (void)seekToTime:(CMTime)time;
詳細運用如下:

//挪動滑塊調整播放進度
- (IBAction)playSliderValueChange:(UISlider *)sender
{
  //依據值計算時間
  float time = sender.value * CMTimeGetSeconds(self.player.currentItem.duration);
  //跳轉到以後指定時間
  [self.player seekToTime:CMTimeMake(time, 1)];
}

8、監聽音樂播放完成

普通音視頻播放完成時我們或多或少的都要處置一些業務,比方循環播放,播完加入界面等等。上面看下如何監聽AVPlayer的播放完成。

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

這裡是采用注冊監聽AVPlayerItemDidPlayToEndTimeNotification告訴,當AVPlayer一播放完成時,便會收回這個告訴,我們收到告訴後停止處置即可

9、設置音樂後台播放

我們知道運轉在IOS零碎下的順序一旦進入後台就會處於休眠形態,順序中止運轉了,也就播放不了什麼音樂了。但是有一些特定功用的app還是處於可當前台運轉的,比方音樂類型的app正處於這個范圍。但是,並不是說你在使用中播放音樂就能後台萬事大吉的運轉了,你仍然需求做如下幾步操作:

(1)開啟後台形式

target ->capabilities-> Background modes ->翻開開關 ->勾選第一個選項

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

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

以上兩步設置無誤,順序進入後台形式,便可以停止音樂播放

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

我們看百度音樂鎖頻時,也仍然能在屏幕上展現歌曲的信息,以及切換歌曲等。上面看看這個功用是如何完成的:

//音樂鎖屏信息展現
- (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];
}

這裡設置圖片時需求留意下,異步加載網絡圖片後再設置是有效的,所以圖片信息最好是先懇求上去後再停止設置。

近程超控的回調如下:

//監聽近程交互辦法
- (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;
  }
}

三、總結

最後,畫了一張圖總結下播放近程網絡音樂的流程:

依據QQ音樂的界面做了個小demo,上面是demo的真機前台和後台播放的運轉效果:

四、完畢語

播放近程網絡音樂的中心技術點根本上曾經寫完,當然AVPlayer還有很多弱小的功用沒有寫出來,有興味的可以進一步發掘。寫到這裡曾經疲倦至極,後續會繼續更新一些精彩的技術點,也希望大家多多支持本站。

【iOS完成播放近程網絡音樂的中心技術點總結】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved