如何创建一个在后台正常运行的iOS闹钟

问题描述 投票:0回答:1

我想在我正在开发的iOS应用程序中插入闹钟功能,作为参考,我安装了一个名为“Alarmy”的流行应用程序。

我设法让我的应用程序在后台运行,仅使用 AVAudioSession 属性;但是,我注意到该应用程序在手机睡眠期间会消耗大量电池。

经过一些测试,我认为这是由于应用程序在 AVAudioSession 激活后立即激活扬声器(并保持打开状态)所致。

即使在触发audioPlayer.play(atTime:audioPlayer.deviceCurrentTime + Double(秒))之前没有实际的声音播放,如果我非常靠近我的iPhone 7扬声器,我可以听到轻微的嗡嗡声表示扬声器已打开。这意味着扬声器实际上正在播放“空声音”。

用Alarmy设置闹钟时,不存在这种蜂鸣声;它只是在应该播放的时候开始播放。

我没有找到任何其他方法来在后台维护我的应用程序并在指定时间播放闹钟声音。当然,有本地通知,但它们不允许在手机静音时播放声音。

回到“警报”,我看到他们不仅能够在不需要先激活扬声器的情况下播放后台警报,而且还能够在后台将音量调到最大。他们是否可能触发其他一些 iOS 后台模式来实现这些目标,也许以某种巧妙的方式使用后台获取或处理?有没有已知的方法可以复制这些行为?

提前致谢!

这是我用来设置闹钟的当前代码:

private func setNewAlarm(audioPlayer: AVAudioPlayer, seconds: Int, ringtone: String) {

        do {

            self.setNotificationAlarm(audioPlayer: audioPlayer, seconds: seconds, ringtone: ringtone, result: result) 
            //This calls the method I use to set a secondary alarm using local notifications, just in case the user closes the app

            try AVAudioSession.sharedInstance().setActive(false)
            try AVAudioSession.sharedInstance().setCategory(.playback, options: [ .mixWithOthers])
            try AVAudioSession.sharedInstance().setActive(true)

        } catch let error as NSError {
            print("AVAudioSession error: \(error.localizedDescription)")
        }

        audioPlayer.prepareToPlay()

        audioPlayer.play(atTime: audioPlayer.deviceCurrentTime + Double(seconds))

        result(true)

    }
ios swift avaudioplayer alarm avaudiosession
1个回答
0
投票

为了确保您的应用程序不会耗尽电池,您可以尝试仅在闹钟应该播放之前激活 AVAudioSession。这将防止扬声器不必要地持续打开,从而节省电池寿命。安排本地通知作为备份,这样即使应用程序在后台或手机处于静音状态,闹钟也会响起。

这是我用 swift 编写的代码来帮助您:

import AVFoundation
import UserNotifications

private func setNewAlarm(audioPlayer: AVAudioPlayer, seconds: Int, ringtone: String) {

    // Schedule a local notification as a backup
    let content = UNMutableNotificationContent()
    content.title = "Alarm"
    content.body = "Your alarm is ringing!"
    content.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: "\(ringtone).caf"))

    let trigger = UNTimeIntervalNotificationTrigger(timeInterval: TimeInterval(seconds), repeats: false)
    let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)

    UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
    
    // Activate audio session shortly before the alarm time to save battery
    DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(seconds - 5)) {
        do {
            try AVAudioSession.sharedInstance().setCategory(.playback, options: [.mixWithOthers])
            try AVAudioSession.sharedInstance().setActive(true)
        } catch {
            print("AVAudioSession error: \(error.localizedDescription)")
        }

        // Prepare and play the alarm sound
        audioPlayer.prepareToPlay()
        audioPlayer.play(atTime: audioPlayer.deviceCurrentTime + 5)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.