【问题标题】:SwiftUI · Background timer works on simulator but not on real deviceSwiftUI · 后台定时器在模拟器上工作,但在真实设备上不工作
【发布时间】:2020-07-10 22:32:49
【问题描述】:

我正在尝试构建一个计时器,当应用程序在后台甚至屏幕被锁定时,它会继续倒计时。计时器达到 0 后,应发送通知。

到目前为止,它可以在模拟器上运行,但不能在真实设备上运行(iPhone X,运行 iOS 13.5.1)。进入后台时任务只是暂停。

如何在真实设备上保持倒计时?

import SwiftUI
import UserNotifications

struct ContentView: View {
    @State var start = false
    @State var count = 10 // 10 sec timer
    @State var time = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    
    var body: some View{
        VStack{
            Text("\(self.count)")
            
            Button(action: {
                self.start.toggle()
            }) {
                Text("Start")
            }
        }
        .onAppear(perform: {
            UNUserNotificationCenter.current().requestAuthorization(options: [.badge,.sound,.alert]) { (_, _) in
            }
        })
            .onReceive(self.time) { (_) in
                if self.start{
                    if self.count != 0{
                        self.count -= 1
                    }
                    else{
                        self.sendNotification()
                    }
                }
        }
    }
    
    func sendNotification(){
        
        let content = UNMutableNotificationContent()
        content.title = "Timer"
        content.body = "Time is up!"
        
        let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
        let req = UNNotificationRequest(identifier: "MSG", content: content, trigger: trigger)
        
        UNUserNotificationCenter.current().add(req, withCompletionHandler: nil)
    }
}

【问题讨论】:

  • Timer 在您的应用暂停时不会运行。您可以使用Timer 来更新您的用户界面,但您不能使用简单的计数器来跟踪时间。您需要计算计时器的结束日期并使用它来确定时间到了。如果您的应用有可能在发生这种情况时被暂停,您可以考虑在计时器到期时安排通知

标签: ios swiftui


【解决方案1】:

Apple 不允许计时器在后台运行。

有关更多信息,请参阅以下两个问题:

Apple 不允许您在应用程序后台运行后长时间运行进程。来自文档:

实现长时间运行的任务

对于需要更多执行时间来执行的任务,您必须请求特定权限才能在后台运行它们而不会被暂停。在 iOS 中,只允许特定类型的应用程序在后台运行: ]

  • 在后台向用户播放有声内容的应用,例如音乐播放器应用
  • 在后台录制音频内容的应用程序
  • 让用户随时了解其位置的应用,例如导航应用
  • 支持互联网协议语音 (VoIP) 的应用
  • 需要定期下载和处理新内容的应用
  • 从外部附件接收定期更新的应用
  • 实现这些服务的应用必须声明它们支持的服务并使用系统框架来实现这些服务的相关方面。

声明服务让系统知道您使用了哪些服务,但在某些情况下,实际上是系统框架阻止了您的应用程序被挂起。

但在这种情况下,您想发送通知,所以我建议您做一些类似的事情,但要有所不同。

当用户离开应用程序时,您想要获取当前时间。然后,您希望将剩余计时器时间添加到当前时间,并在您的应用中运行代码以在当前时间 + 计时器剩余时间发送通知。

在特定时间发送通知的代码可以查看here

let content = UNMutableNotificationContent()
                content.title = "Title"
                content.body = "Body"
                content.sound = UNNotificationSound.default()

                let gregorian = Calendar(identifier: .gregorian)
                let now = Date()
                var components = gregorian.dateComponents([.year, .month, .day, .hour, .minute, .second], from: now)

                // Change the time to 7:00:00 in your locale
                components.hour = 7
                components.minute = 0
                components.second = 0

                let date = gregorian.date(from: components)!

                let triggerDaily = Calendar.current.dateComponents([.hour,.minute,.second,], from: date)
                let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDaily, repeats: true)


                let request = UNNotificationRequest(identifier: CommonViewController.Identifier, content: content, trigger: trigger)
                print("INSIDE NOTIFICATION")

                UNUserNotificationCenter.current().add(request, withCompletionHandler: {(error) in
                    if let error = error {
                        print("SOMETHING WENT WRONG")
                    }
                })

【讨论】:

    猜你喜欢
    • 2016-05-29
    • 1970-01-01
    • 1970-01-01
    • 2014-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-09
    • 2017-11-14
    相关资源
    最近更新 更多