利用 AVPlayer 播放音樂音效

彼得潘的生活不能沒有音樂,尤其是在寫 code 的時候。因此接下來就讓我們認識既能播放 App 裡的歌曲,也能播放網路上歌曲的音樂播放器, AVPlayer ! (ps: 其實不只音樂,它也能播放影片。)

下載音樂

為了有音樂可播,先讓我們從 Youtube 找歌。比方查詢 Youtube 影片楊宗緯一次就好的影片網址。

參考以下連結的方法,我們可下載 Youtube 影片的 mp3 檔。

將音樂加到 Xcode 專案

利用 AVPlayer 播放 App 裡的音樂

以下範例分別示範在 SwiftUI & UIKit App 畫面出現時播放音樂。

SwiftUI 版本

import SwiftUI
import AVFoundation

struct ContentView: View {

@State private var player = AVPlayer()

var body: some View {
Text("原來你是我最想留住的幸運")
.onAppear {
let url = Bundle.main.url(forResource: "黑色毛衣", withExtension: "mp3")!
let playerItem = AVPlayerItem(url: url)
player.replaceCurrentItem(with: playerItem)
player.play()
}
}
}

UIKit 版本

import UIKit
import AVFoundation

class ViewController: UIViewController {

let player = AVPlayer()

override func viewDidLoad() {
super.viewDidLoad()

let url = Bundle.main.url(forResource: "黑色毛衣", withExtension: "mp3")!
let playerItem = AVPlayerItem(url: url)
player.replaceCurrentItem(with: playerItem)
player.play()
}
}

說明:

  • 加入 AVFoundation 函式庫(framework)
import AVFoundation

為了使用 AVPlayer 播放音樂,必須先加入 AVFoundation。

  • 宣告 AVPlayer 型別的 property player。

SwiftUI 的寫法。

@State private var player = AVPlayer()

UIKit 的寫法。

let player = AVPlayer()

生成播放音樂的 AVPlayer 物件。

  • 設定 player 播放的音樂並開始播放。
let url = Bundle.main.url(forResource: "黑色毛衣", withExtension: "mp3")!
let playerItem = AVPlayerItem(url: url)
player.replaceCurrentItem(with: playerItem)
player.play()

(1) 產生音樂在 App 裡路徑的 URL。

let url = Bundle.main.url(forResource: "music", withExtension: "mp3")!

利用 Bundle.man 取得 App 主要的 Bundle,也就是 App 本身的資料夾。放在 Project navigator 下的 music.mp4 將在 App 的資料夾下,透過呼叫 function url(forResource:withExtension:) 可取得它在資料夾裡的 URL,參數 forResource 傳入檔名,參數 withExtension 傳入附檔名。

func url(forResource name: String?, withExtension ext: String?) -> URL?

值得注意的,function url 回傳的 URL 將是 optional ,因此我們加上 ! 取值。假設我們不會手殘,檔名不會打錯,因此我們可以放心加上 !。

(2) 利用 AVPlayerItem 生成要播放的音樂。

let playerItem = AVPlayerItem(url: fileUrl)

(3) 設定 player 要播放的 AVPlayerItem。

player.replaceCurrentItem(with: playerItem)

(4) 開始播放音樂。

player.play()

現在 App 啟動後,將可立即聽到美妙的音樂。

也許有人有疑問,為何不在 SwiftUI 範例的 onAppear 或 UIKit 範例的 viewDidLoad 裡產生 AVPlayer 物件,而是另外宣告 property 儲存呢 ? 比方以下我們在 function onAppear 裡宣告常數 player。

struct ContentView: View {

var body: some View {
Text("Hello, World!")
.onAppear {
let player = AVPlayer()
let url = Bundle.main.url(forResource: "黑色毛衣", withExtension: "mp3")!
let playerItem = AVPlayerItem(url: url)
player.replaceCurrentItem(with: playerItem)
player.play()
}
}
}

剛剛的程式還是可以執行,但我們完全聽不到音樂,因為常數 player 是在 onAppear 的 { } 裡生成,所以 onAppear 執行完後,player 就會被殘忍地結束生命,它連一秒鐘的音樂都來不及唱出。

利用 AVPlayer 播放網路上的音樂

我們也可以用 AVPlayer 播放網路上的音樂,只要在生成 AVPlayerItem 時傳入網路上音樂的 URL,比方以下例子:

let url = URL(string: "https://audio-ssl.itunes.apple.com/apple-assets-us-std-000001/AudioPreview118/v4/69/0e/98/690e98db-440d-cb0c-2bff-91b00a05bdda/mzaf_1674062311671795807.plus.aac.p.m4a")!
let playerItem = AVPlayerItem(url: url)

暫停音樂

呼叫 function pause。

player.pause()

調整音量

volum 的大小是 0 ~ 1。

player.volume = 0.8

volume 控制的音量是相對於系統的音量,如下圖所示,倘若此時系統的音量是一半的音量,那麼就算 volume 等於 1 也會只有一半的音量。

如果想要調整系統的音量,可直接在畫面上加入 MPVolumeView。加入前記得先 import MediaPlayer,然後請在實機測試,因為它無法在模擬器測試。

let volumeView = MPVolumeView(frame: CGRect(x: 10, y: 100, width: 300, height: 40))
view.addSubview(volumeView)

播放下一首 / 上一首歌

AVPlayer 播放的音樂由 AVPlayerItem 控制,因此我們只要呼叫 function replaceCurrentItem(with:),傳入下一首,上一首歌的 URL,即可改變播放的音樂。

比方下一首歌是周興哲的你好不好,播放的程式如下:

let url = Bundle.main.url(forResource: "你好不好", withExtension: "mp4")!
let playerItem = AVPlayerItem(url: url)
player.replaceCurrentItem(with: playerItem)

判斷目前是否正在播放歌曲

if player.timeControlStatus == .playing {

}

取得歌曲目前播放到第幾秒

player.currentTime().seconds

取得目前播放歌曲的長度

player.currentItem?.duration

調整歌曲播放的區段(SEEK)

利用 seek 控制歌曲播放的區段。

從頭播放。

player.seek(to: .zero)

從第 30 秒開始播放。

let time = CMTime(value: 30, timescale: 1)
player.seek(to: time)

timeScale 通常會傳 1,value / timescale 表示秒數,因此 CMTime(value: 30, timescale: 2) 將變成第 15 秒。

歌曲播放完的通知,AVPlayerItemDidPlayToEndTime

很多時候我們想知道歌曲播完了,比方想在周興哲的你好不好唱完後,繼續播放五月天的好好。

我們可在音樂播完了收到 Notification,此時它會發送通知AVPlayerItemDidPlayToEndTime。

NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil, queue: .main) { _ in
print("finish, next song")
}

偵測歌曲目前播放的時間

產生 AVPlayer 的多種方法

如果一開始已知道播放的歌曲,也可以在產生 AVPlayer 時傳入 playerItem 或 url。

重覆播放音樂

剛剛的程式已經可以順利播放音樂,可惜它只能播放一次。若覺得一次不夠好,想多聽幾次的朋友,可參考以下連結利用 AVPlayerLooper 實現重覆播放。

背景播放音樂

背景控制音樂

免費音效網站

免費背景音樂網站

作品集

--

--

彼得潘的 iOS App Neverland
彼得潘的 Swift iOS App 開發問題解答集

彼得潘的iOS App程式設計入門,文組生的iOS App程式設計入門講師,彼得潘的 Swift 程式設計入門,App程式設計入門作者,http://apppeterpan.strikingly.com