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

Eri*_*ric 6 nsnotificationcenter ios avaudiosession swift usernotifications

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

例如,当手机处于静音模式时,通知会成功播放声音(好吧,太棒了!)。然而,当手机在静默模式下,声音不玩了,即使该应用程序在后台运行还是(没那么大......)。

我知道静音模式应该使所有通知声音静音,但我已经从 App Store 下载了其他闹钟应用程序(如 Alarmy),即使手机处于静音状态,它们也能以某种方式播放通知声音模式,只要应用程序仍在后台运行。只有当应用程序完全退出时,静音模式才会生效。

有谁知道如何实现这个结果?是否需要在代码或 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)
    }
}
Run Code Online (Sandbox Code Playgroud)

我设置通知的代码:

/// 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
        }
    })
}
Run Code Online (Sandbox Code Playgroud)

Eri*_*ric 6

所以我发现了一些东西。

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

然而,好消息!

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

注意:我(最终)从这个精彩的 SO answer 中发现了这个解决方案,但我会在这里总结以供参考。

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

脚步

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

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

do {
    try AVAudioSession.sharedInstance().setCategory(.playAndRecord)
    try AVAudioSession.sharedInstance().setActive(true)
} catch {
    print(error.localizedDescription)
}
Run Code Online (Sandbox Code Playgroud)
  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.
Run Code Online (Sandbox Code Playgroud)

总之,正如我上面链接的 SO 答案如此恰当地总结了:

这不会在后台播放静音,这违反了Apple的规则。它实际上启动了播放器,但音频只会在正确的时间启动。我认为这可能是 Alarmy 实现他们警报的方式,因为它不是触发音频的远程通知,也不是本地通知播放的音频(因为它不限于 30 秒或被振铃开关静音)。