应用在后台时本地通知声音无法播放 - Swift

8
我正在制作一个闹钟应用程序,我确认我的闹钟通知被正确触发了,但是声音并不总是按照我预期的播放。
例如,当手机没有静音时,通知会成功地播放声音(好的!)。然而,当手机处于静音模式时,即使应用程序仍在后台运行,声音也不会播放(不太好)。
我知道静音模式应该消除所有通知声音,但我从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)
    }
}

我设置通知的代码:

/// 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
        }
    })
}

1
实际上,您正在冒苹果在审核期间拒绝您的应用程序的风险,因为在静音模式下运行应用程序时不允许使用框架播放声音。但是,如果您仍然想冒险,请查看此链接:http://andrewmarinov.com/building-an-alarm-app-on-ios/ - Climbatize
不幸的是,将音频会话设置为.playAndRecord并在Required Background Modes的.plist文件中启用音频似乎不起作用...(来自链接文章中的“麦克风方法”)。 - Eric
音频文件长度不能超过30秒。 - Ramis
有人有可行的解决方案吗?(或者@Climbatize,您能详细说明一下您是否能够使麦克风方法起作用吗?) - Eric
2
@Climbatize 感谢您的贡献。如果您好奇我是如何解决它的,请查看下面的答案。 - Eric
显示剩余2条评论
1个回答

10

我发现了一些事情。

按照问题陈述,目前在静音模式下无法在本地通知中播放声音。

然而,好消息来了!

实际上,有一种不同的方法可以实现相同的效果;这就是 Alarmy 等应用程序所使用的方法。

注意:我(终于)从这个非常好的 SO 回答中发现了这个解决方案,但我将在此简要概括它以供参考。

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

步骤

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

  2. 在您的应用程序委托中,将您的 AVAudioSession 的类别设置为.playBack,这样即使手���处于锁定或后台状态下,声音仍将播放。

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 答案所总结的那样:
这个方法不会在后台播放静音,这违反了苹果的规定。它实际上启动了播放器,但音频只会在正确的时间开始播放。我认为这可能是 Alarmy 实现他们的闹钟的方式,因为它不是通过远程通知触发音频,也不是通过本地通知播放音频(因为它不受 30 秒限制或静音模式开关的限制)。

1
很好的发现,我很高兴你终于解决了问题,只是在提交到AppStore时要小心一点 ;) - Climbatize
这会不会停止用户正在播放的其他音频?比如他们正在听音乐。 - Mor Blau
@MorBlau 当然,当警报响起时,这不是你想要的吗?但是,如果您希望获得不同的音频结果(例如.mixWithOthers.duckOthers等),则在设置应用程序的AVAudioSession类别时,还可以配置其他选项 - Eric
1
你可以将 audioPlayer.deviceCurrentTime 视为“现在”(即使它是一些奇怪的大 Double/TimeInterval),并且将 timeOffset 视为从现在开始的 5 秒钟(假设你将我的解决方案中的 timeInterval 常量设置为 5.0 而不是 60.0)。 - Eric
1
嗯...我不这么认为。通知并不是让应用程序保持“唤醒”状态所必需的。事实上,我也不知道预定的声音是否会让应用程序保持唤醒状态(不确定苹果在这方面的工作原理)。本帖子特定于“如何在未来的某个预定时间播放声音”的问题。你不能仅仅将这种情况应用于“保持应用程序唤醒”,以便你可以在应用程序处于后台时随时注册跌倒/震动。此外,如果你滥用预定的声音播放器来保持应用程序活动状态,苹果几乎肯定会拒绝你的应用程序。 - Eric
显示剩余10条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接