应用程序在后台时不播放本地通知声音 - Swift

Local notification sound not playing while app in background - Swift

我正在制作一个闹钟应用程序,我已经确认我的闹钟通知被正确触发,但声音并不总是像我预期的那样播放。

例如,当 phone 是 而非 静音模式时,通知成功播放声音(好的,太棒了!)。但是,当 phone 处于静音模式时,声音不会播放,即使该应用程序仍在 运行 后台(不太好...)。

我知道静音模式应该使所有通知声音静音,但我已经从 App Store 下载了其他闹钟应用程序(如 Alarmy),即使phone 处于静音模式,只要该应用程序仍在后台 运行。静默模式只有在应用程序完全退出后才会生效。

有谁知道如何实现这个结果?是否需要在我的代码或 plist 文件中声明某些设置或选项?我已经搜索了互联网,但没有找到任何关于这个特定问题的信息...

我设置AVAudioSession类别的代码:

private func setAudioCategory() {
    do {
        // Enable sound (even while in silent mode) as long as app is in foreground.
        try AVAudioSession.sharedInstance().setCategory(.playback)
    }
    catch {
        print(error.localizedDescription)
    }
}

我设置通知的代码:

/// Sets a local user notification for the provided `Alarm` object.
static func set(_ alarm: Alarm) {

    // Configure the notification's content.
    let content = UNMutableNotificationContent()
    content.title = NSString.localizedUserNotificationString(forKey: K.Keys.notificationTitle, arguments: nil)
    content.body = NSString.localizedUserNotificationString(forKey: K.Keys.notificationBody, arguments: nil)

    // Get sound name
    let soundName: String = UserDefaultsManager.getAlarmSound().fileNameFull
        
    // Set sound
    content.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: soundName))
    content.categoryIdentifier = "Alarm"

    // Configure the time the notification should occur.
    var date = DateComponents()
    date.hour = alarm.hour
    date.minute = alarm.minute

    // Create the trigger & request
    let trigger = UNCalendarNotificationTrigger(dateMatching: date, repeats: false)
    let request = UNNotificationRequest(identifier: alarm.notifID, content: content, trigger: trigger)

    // Schedule the request with the system.
    let notificationCenter = UNUserNotificationCenter.current()
    notificationCenter.add(request, withCompletionHandler: { error in
        if error != nil {
            // TODO: Show Alert for Error
            return
        }
    })
}

所以我发现了一些东西。

正如问题所述,当 phone 处于静音模式时,目前无法在本地通知中播放声音。

不过,好消息!

实际上有一种不同的方法可以达到相同的结果;这就是 Alarmy 等应用程序的工作方式。

Note: I (FINALLY) discovered this solution from this wonderful SO answer, but I'll summarize it here for reference.

简而言之,本地通知不会播放声音,而是由应用播放(在后台时)。

步骤

  1. 您必须启用该应用程序才能在后台播放声音。为此,导航到您的 .plist 文件并将字符串值 App plays audio or streams audio/video using AirPlay 添加到数组键 Required background modes。 (这也可以在您的应用程序 Capabilities 中实现 - 它做同样的事情)。

  2. 在您的 App Delegate 中,将 AVAudioSession 的类别设置为 .playBack,这样即使 phone 被锁定或处于后台,声音仍会播放。

do {
    try AVAudioSession.sharedInstance().setCategory(.playAndRecord)
    try AVAudioSession.sharedInstance().setActive(true)
} catch {
    print(error.localizedDescription)
}
  1. 在您希望播放的时间启动您的 AVAudioPlayer(在我的例子中,在我收到本地通知时)。​​
let timeInterval = 60.0 // 60.0 would represent 1 minute from now
let timeOffset = audioPlayer.deviceCurrentTime + timeInverval
audioPlayer.play(atTime: timeOffset) // This is the magic function

// Note: the `timeInterval` must be added to the audio player's 
// `.deviceCurrentTime` to calculate a correct `timeOffset` value.

总而言之,正如我在上面链接的 SO 答案那样恰当地总结了:

This does not play silence in the background, which violates Apple's rules. It actually starts the player, but the audio will only start at the right time. I think this is probably how Alarmy implemented their alarm, given that it's not a remote notification that triggers the audio nor is the audio played by a local notification (as its not limited to 30 seconds or silenced by the ringer switch).