我正在尝试构建一个计时器,当应用程序在后台甚至屏幕被锁定时,该计时器将继续递减计数。计时器达到0后,应该发送通知。
到目前为止,它可以在模拟器上运行,但不能在真实设备(运行iOS 13.5.1的iPhone X)上运行。进入后台后,任务只会暂停。
如何使倒数计时在真实设备上运行?
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)
}
}
答案 0 :(得分:3)
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")
}
})