我正在尝试在我的应用程序中实现一个倒计时器,该计时器也使用实时活动 API。当应用程序最小化时,计时器在动态岛/锁屏中运行。但是,我还没有弄清楚如何在计时器完成并且应用程序在后台时结束实时活动,它只是在到达结束日期后继续计数。
这是我使用的状态:
struct TimerAttributes: ActivityAttributes {
public struct ContentState: Codable, Hashable {
var willEndAt: Date?
var pausedAt: Date?
func getElapsedTimeInSeconds() -> Int {
let now = Date()
guard let willEndAt = self.willEndAt else {
return 0
}
guard let pausedAt = self.pausedAt else {
return Int(now.timeIntervalSince1970 - willEndAt.timeIntervalSince1970)
}
return Int(pausedAt.timeIntervalSince1970 - willEndAt.timeIntervalSince1970)
}
func getPausedTime() -> String {
let elapsedTimeInSeconds = abs(getElapsedTimeInSeconds())
let minutes = (elapsedTimeInSeconds % 3600) / 60
let seconds = elapsedTimeInSeconds % 60
return String(format: "%d:%02d", minutes, seconds)
}
func getTimeIntervalSinceNow() -> Double {
guard let willEndAt = self.willEndAt else {
return 0
}
return willEndAt.timeIntervalSince1970 - Date().timeIntervalSince1970
}
func isRunning() -> Bool {
return pausedAt == nil && willEndAt != nil
}
func isPaused() -> Bool {
return pausedAt != nil
}
}
}
这就是我显示计时器的方式:
Text(
Date(timeIntervalSinceNow: context.state.getTimeIntervalSinceNow()),
style: .timer
)
由于我还在计时器完成时安排了本地通知,所以我的第一个想法是在收到通知时以某种方式取消实时活动,但这仅在用户单击通知或应用程序位于前台时才有效。
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
Task {
for activity in Activity<TimerAttributes>.activities {
await activity.end(nil, dismissalPolicy: .immediate)
}
}
completionHandler([.banner, .sound])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
Task {
for activity in Activity<TimerAttributes>.activities {
await activity.end(nil, dismissalPolicy: .immediate)
}
}
completionHandler()
}
我还尝试在 ActivityContent 中使用“staleDate”属性,但这也不会结束实时活动。
当应用程序在后台时,如何停止实时活动而不使用远程推送通知(因为当用户没有互联网时计时器也应该工作)?
您是否尝试过开始实时活动并立即结束活动,并将解雇政策设置为您首选的结束日期?
activeActivity.end(
ActivityContent(state: TimerAttributes.ContentState(willEndAt: _END_DATE_, pausedAt: _PAUSE_DATE_), staleDate: nil),
dismissalPolicy: .after(date.now.addingTimeInterval(_SECONDS_TO_END_DATE_))
)