Search code examples
swiftmacosunusernotificationcenter

UNNotificationSound doesn't play on macOS. Same file works on iOS


Been pulling my hair for the past week.

What I've learned:

  • Notification sound works on iOS, not macOS
  • Files on ~/Library/Sound (notice the tilde, it's outside the project folder):

    • Some (not all) file played with .m4r and .aiff format fired the sound
    • Sound fired when referencing it without file extension UNNotificationSound("quack")
    • Default sound when referencing it with file extension UNNotificationSound("quack.m4r")
  • Files on on root project directory (/), or on Library/Sound:

    • For sound that played on ~/Library/Sounds:
      • No notification sound (silent) when referencing it without file extension quack
      • Default sound when referencing it with file extension quack.m4r
    • For sound that played not played ~/Library/Sounds:
      • Anything will play default notification sound.

Here's the code I used on appDelegate

let center = UNUserNotificationCenter.current()
        center.delegate = self

        let cont = UNMutableNotificationContent()
        cont.title = "Test notification"
        let sound = UNNotificationSoundName("eventually.m4r")
        cont.sound = UNNotificationSound(named: sound)
        let req = UNNotificationRequest(identifier: "Ay", content: cont , trigger: nil)
        center.add(req)

I've religiously followed https://developer.apple.com/documentation/usernotifications/unnotificationsound without no avail.

What I've made sure:

  • I put the files (.m4r, .aiff) on root project directory
  • File is included in the bundle
  • target macOS and iOS is checked
  • Sound played on iOS, but not macOS
  • It's less than 30 second

p.s. this might be potentially a macOS bug, but I don't understand how some file works. What's confusing is app like Slack and others could use custom sound notification. I've also had a bug where repeat:true trigger only called once on macOS, but repeatedly on iOS `UNTimeIntervalNotificationTrigger` repeats: true only fired once. macOS bug? Works on iOS


Solution

  • In recently exploring this I found that all of the following need to be true for it to find the sound on Mac:

    1. The sound file must ends up in the Resources folder inside the bundle, not a sub-directory of Resources.

    2. The application must be in Applications. After building from XCode, move/copy the bundle into Applications to test, it won't work if you run it in-place.

    3. The file must've been placed into the bundle by XCode as a resource, it's not enough for it to simply be placed there. (This is not really relevant for XCode devs, but this is a problem using something like Unity as you can't use a simple build step to get the files to the correct place)

    Also, importantly, the OS sometimes remembers when it has looked up a notification sound and failed to find it. So it may be that you had it set up wrong during your first test and then got it set up correctly, but the OS still doesn't play the sound. Test with a new filename or reboot the Mac to be sure.