SwiftUI · 后台计时器在模拟器上工作,但在真实设备上不起作用 [英] SwiftUI · Background timer works on simulator but not on real device

查看:32
本文介绍了SwiftUI · 后台计时器在模拟器上工作,但在真实设备上不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Im trying to build a timer which continuing counting down when the app is in the background or even the screen is locked. After the timer reached 0 a notification should been send.

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

So far it works on the simulator but not on the real device (iPhone X, running iOS 13.5.1). The task simply pauses when entering background.

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

How do I keep the countdown running on the real device?

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

推荐答案

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

Apple will not allow timers to run in the background.

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

For more information see these two questions:

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

Apple will not allow you to run processes for long periods of time after your app has been backgrounded. From the docs:

实施长时间运行的任务

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

For tasks that require more execution time to implement, you must request specific permissions to run them in the background without their being suspended. In iOS, only specific app types are allowed to run in the background: ]

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

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

Declaring the services lets the system know which services you use, but in some cases it is the system frameworks that actually prevent your application from being suspended.

  • 应用关闭时在后台"运行计时器
  • 但在这种情况下,您想发送通知,所以我建议做一些类似但稍有不同的事情.

    But in this case you want to send a notification, so I suggest doing something similar but with a twist.

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

    When the user leaves the app, you want to get the current time. You then want to add the remaining timer time to the current time and run code in your app to send a notification at current time + timer remaining time.

    可以在此处查看用于在特定时间发送通知的代码:

    Code for sending a notification at a specific time can be viewed 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")
                        }
                    })
    

    这篇关于SwiftUI · 后台计时器在模拟器上工作,但在真实设备上不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆