作業6-2: 模仿 iOS 的 Music App 製作情歌點唱機,可忽略進階功能

Baaro
彼得潘的 Swift iOS / Flutter App 開發教室
8 min readJul 27, 2020
Photo by Kara Eads on Unsplash

主要功能

  1. 播放/暫停
  2. 上、下一首
  3. 更新image、歌手名稱、歌曲名稱
  4. Slider 調整播放進度
  5. Slider 播放進度時間、總時間
  6. 音量調整(非系統)
  7. 隨機播放、循環播放、單曲播放
  8. 背景&鎖定播放
  9. 背景播放時,系統可控制播放、上下一首並顯示歌曲資訊

音樂播放相關的程式碼就不額外放上來了,

只提一些我覺得比較重要的東西。

func updatePlayerUI() {
//更新總時間& Slider 的Value
guard let duration = playerItem?.asset.duration else {
return
}
//轉為歌曲的總時間
let seconds = CMTimeGetSeconds(duration)
//在Label顯示歌曲總時間
totalPlayLabel.text = formatConversion(time: seconds)
slider.minimumValue = 0
slider.maximumValue = Float(seconds)
slider.isContinuous = true
}

取歌曲的總時間(秒),並設定slider。

func CurrentTime() {
//監聽現在播放時間&換Slider的Value
player.addPeriodicTimeObserver(forInterval: CMTimeMake(value: 1, timescale: 1), queue: DispatchQueue.main, using: { (CMTime) in
if self.player.currentItem?.status == .readyToPlay {
let currentTime = CMTimeGetSeconds(self.player.currentTime())
self.slider.value = Float(currentTime)
self.nowPlayLabel.text = self.formatConversion(time: currentTime)
}
})
}

現在播放時間,並更新Slider Value and Label Text。

func checkMusicIsEnd(){
//偵測是否播放到最後
NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil, queue: .main) { (_) in
if self.repeatOnePlay{
//回到0秒 繼續播放
let targetTime:CMTime = CMTimeMake(value: 0, timescale: 1)
self.player.seek(to: targetTime)
self.player.play()
}else{
self.playNextMusic()
}
}
}

播放完畢後的動作。

    func createPlayAry(){
//創建playArray
for i in 0 ..< musicList.count{
playAry.append(i)
}

}
func sortPlayAry(){
//playArray 清單排序
playAry.sort()
}
func shufflePlayAry(){
//playArray 清單亂序排序
playAry.shuffle()
}

播放列表,亂序or排序。

設定背景&鎖定播放

//  設定背景&鎖定播放
func setupRemoteTransportControls() {
// Get the shared MPRemoteCommandCenter
let commandCenter = MPRemoteCommandCenter.shared()

// Add handler for Play Command
commandCenter.playCommand.addTarget { [unowned self] event in
if self.player.rate == 0.0 {
self.player.play()
return .success
}
return .commandFailed
}

// Add handler for Pause Command
commandCenter.pauseCommand.addTarget { [unowned self] event in
if self.player.rate == 1.0 {
self.player.pause()
return .success
}
return .commandFailed
}
commandCenter.nextTrackCommand.addTarget{ [unowned self] event in
self.playNextMusic()
return .success
}
commandCenter.previousTrackCommand.addTarget{ [unowned self] event in
self.playPreviousMusic()
return .success
}
}

playCommand :背景播放按鈕設定。

pauseCommand:背景暫停按鈕設定。

nextTrackCommand:背景下一首按鈕設定。

previousTrackCommand:背景上一首按鈕設定。

上下一首的.success不確定有沒有必要加入,可能需要在試試看才知道了。

另外,調整系統音量內建好像已經幫你用好了,不用在自己加入。

commandCenter還有其他的東西可以用,有興趣的可以在自己研究。

背景播放時的歌曲資訊

//  設定背景播放的歌曲資訊
func setupNowPlaying() {
// Define Now Playing Info
let songName:String = (self.musicList[playAry[playNum]].trackName)
let artistName:String = (self.musicList[playAry[playNum]].artistName)
let albumImage:String = (self.musicList[playAry[playNum]].previewName)
var nowPlayingInfo = [String : Any]()
nowPlayingInfo[MPMediaItemPropertyTitle] = songName
nowPlayingInfo[MPMediaItemPropertyAlbumTitle] = artistName

if let image = UIImage(named: albumImage) {
nowPlayingInfo[MPMediaItemPropertyArtwork] =
MPMediaItemArtwork(boundsSize: image.size) { size in
return image
}
}
nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = player.currentTime().seconds
nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = player.currentItem?.asset.duration.seconds
nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = player.rate

// Set the metadata
MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
}

圖片、歌手、歌曲名稱。

建議大家參考Apple 文檔會比較不被我誤導XD

參考連結

背景播放

背景控制播放

AVFile格式

--

--