ios - SwiftUI · 后台计时器在模拟器上有效,但在真实设备上无效

标签 ios swiftui

我正在尝试构建一个计时器,该计时器会在应用程序处于后台甚至屏幕锁定时继续倒计时。计时器达到 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)
    }
}

Selected background Modes (Screenshot)

最佳答案

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

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

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

Implementing Long-Running Tasks

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: ]

  • Apps that play audible content to the user while in the background, such as a music player app
  • Apps that record audio content while in the background
  • Apps that keep users informed of their location at all times, such as a navigation app
  • Apps that support Voice over Internet Protocol (VoIP)
  • Apps that need to download and process new content regularly
  • Apps that receive regular updates from external accessories
  • Apps that implement these services must declare the services they support and use system frameworks to implement the relevant aspects of those services.

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.

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

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

在特定时间发送通知的代码可以查看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")
                    }
                })

关于ios - SwiftUI · 后台计时器在模拟器上有效,但在真实设备上无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62843181/

相关文章:

ios - CGBitmapContextCreate : unsupported parameter combination

ios - 注册推送通知功能不会被调用

ios - 如何使用 TableView 项目访问 Swift 2 中的 View Controller ?

ios - 代理未调用协议(protocol)方法

ios - 将 TextEditor 文本计数连接到 SwiftUI 中的 ProgressView

swiftui - 如何刷新指向同一 URL 的 AsyncImage

应用程序购买中的 IO - 沙盒的报告/交易日志

ios - 使用 SwiftUI 的 TextField 描边边框文本

macos - 有没有办法不显示 SwiftUI 生命周期 macOS 应用程序的窗口?

ios - SwiftUI NavigationLink push in onAppear 使用@ObservableObject 时立即弹出 View