Phát audio/video là nhu cầu cơ bản hầu hết app. iOS cung cấp AVFoundation framework mạnh mẽ.
Framework & Setup
Project → Target → Build Phases → Link Binary With Libraries → Thêm AVFoundation.framework.

Phát Audio (AVAudioPlayer)
Bước 1: Thêm file audio vào project
Kéo file .mp3, .m4a, .wav... vào project (Copy items if needed).
Bước 2: Code
import UIKit
import AVFoundation
class ViewController: UIViewController {
var audioPlayer: AVAudioPlayer?
@IBAction func playButton(_ sender: Any) {
guard let url = Bundle.main.url(forResource: "sample", withExtension: "mp3") else {
print("Không tìm thấy file audio")
return
}
do {
audioPlayer = try AVAudioPlayer(contentsOf: url)
audioPlayer?.prepareToPlay()
audioPlayer?.play()
print("Đang phát audio...")
} catch {
print("Lỗi phát audio: \(error)")
}
}
@IBAction func stop(_ sender: Any) {
audioPlayer?.stop()
audioPlayer = nil // Release memory
}
@IBAction func pause(_ sender: Any) {
audioPlayer?.pause()
}
}
Phát Video (AVPlayer + AVPlayerLayer)
Bước 1: Thêm file video (.mp4, .mov) vào project
Bước 2: Code
import AVFoundation
class ViewController: UIViewController {
var player: AVPlayer?
var playerLayer: AVPlayerLayer?
@IBAction func videoButton(_ sender: Any) {
guard let path = Bundle.main.path(forResource: "one", ofType: "mp4") else {
print("Không tìm thấy video")
return
}
let videoURL = URL(fileURLWithPath: path)
player = AVPlayer(url: videoURL)
playerLayer = AVPlayerLayer(player: player)
playerLayer?.frame = view.bounds
playerLayer?.videoGravity = .resizeAspect // Giữ tỷ lệ
if let layer = playerLayer {
view.layer.addSublayer(layer)
}
player?.play()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
playerLayer?.frame = view.bounds // Cập nhật frame khi rotate
}
}
Mã hoàn chỉnh
import UIKit
import AVFoundation
class ViewController: UIViewController {
var audioPlayer: AVAudioPlayer?
var player: AVPlayer?
var playerLayer: AVPlayerLayer?
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func stop(_ sender: Any) {
audioPlayer?.stop()
audioPlayer = nil
}
@IBAction func playButton(_ sender: Any) {
guard let url = Bundle.main.url(forResource: "sample", withExtension: "mp3") else { return }
do {
audioPlayer = try AVAudioPlayer(contentsOf: url)
audioPlayer?.play()
} catch { print("Audio error: \(error)") }
}
@IBAction func videoButton(_ sender: Any) {
guard let path = Bundle.main.path(forResource: "one", ofType: "mp4") else { return }
let videoURL = URL(fileURLWithPath: path)
player = AVPlayer(url: videoURL)
playerLayer = AVPlayerLayer(player: player)
playerLayer?.frame = view.bounds
playerLayer?.videoGravity = .resizeAspect
if let layer = playerLayer { view.layer.addSublayer(layer) }
player?.play()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
playerLayer?.frame = view.bounds
}
deinit {
player?.pause()
player = nil
audioPlayer?.stop()
}
}
Các tính năng nâng cao
1. Audio Session (Background audio, ducking...)
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
try AVAudioSession.sharedInstance().setActive(true)
} catch { print("Audio session error: \(error)") }
2. Remote URL Streaming
// Audio streaming
let url = URL(string: "https://example.com/audio.mp3")!
audioPlayer = try AVAudioPlayer(contentsOf: url) // Chỉ file local
// Streaming dùng AVPlayer
player = AVPlayer(url: url)
// Video streaming
player = AVPlayer(url: URL(string: "https://example.com/video.mp4")!)
3. PiP (Picture in Picture) - iOS 14+
if AVPictureInPictureController.isPictureInPictureSupported() {
let pipController = AVPictureInPictureController(playerLayer: playerLayer!)
pipController.delegate = self
pipController.startPictureInPicture()
}
4. Thư viện cao cấp
- AVPlayerViewController: Built-in UI controls (play/pause, slider, fullscreen, airplay)
- VideoPlayer (SwiftUI):
VideoPlayer(player: player) - Player (GitHub: piemonte/Player) - Wrapper đẹp, dễ dùng
- Kingfisher +
AVPlayercho caching
Lưu ý
- Audio file trong Bundle: dùng
AVAudioPlayer(local, offline, hỗ trợ loop, rate, volume) - Streaming/Remote/Video: dùng
AVPlayer - Luôn handle error (file missing, corrupt, format không hỗ trợ)
- Memory: Release player khi không dùng (deinit, viewWillDisappear)
- Background audio: Cần Capability "Audio, AirPlay, and Picture in Picture" + Audio Session config