coiai Logo

This article is an English translation of the original Japanese post. Read the Japanese original →

How Do You Play Music in SwiftUI?

July 21, 2023

Categories: 未分類

What I was trying to do

I wanted to implement alarm sounds and BGM that could be changed from a settings screen!

The fix

Use Bundle.main.url.

Something like this works fine:

@State private var alarmSoundName: String = "bell"
var endAlarm: URL {
    return Bundle.main.url(forResource: alarmSoundName, withExtension: "mp3")!
}
func playAlarm() {
    do {
        alarmPlayer = try AVAudioPlayer(contentsOf: endAlarm)
        alarmPlayer?.play()
    } catch {
        print("Sound playback failed.")
    }
}

One thing to note: with this approach, you can't reach files that live inside Assets.xcassets.

I just created a folder named something like Sounds and put everything there instead.

What I tried first

Initially, I tried following the same pattern as pulling images — storing the mp3 in Assets.xcassets and loading it with NSDataAsset.

Trying to implement it like the code below didn't work. ⚠️

@State private var alarmSound: String = "bell"
let endAlarm = NSDataAsset(name: alarmSound)!.data

It turns out that in Swift, you can't use a variable when dynamically constructing an NSDataAsset.

Since NSDataAsset has to be initialized at compile time, you can't build it dynamically using a variable.

So instead I used the Bundle.main.url approach, which worked fine with State.