推送通知中能否嵌入倒计时计时器?求非SwiftUI实现方法
无需SwiftUI实现带倒计时的推送通知
完全可以不使用SwiftUI实现这类带倒计时的推送通知,依托UIKit框架结合UserNotifications就能实现和示例图一致的效果,具体实现步骤如下:
1. 申请推送通知权限
首先需要向用户申请推送通知权限,尤其是时间敏感通知权限(确保倒计时通知能及时展示并更新):
import UserNotifications func requestNotificationPermissions() { let center = UNUserNotificationCenter.current() center.requestAuthorization(options: [.alert, .sound, .badge, .timeSensitive]) { granted, error in if let error = error { print("权限申请失败: \(error.localizedDescription)") } } }
2. 创建本地倒计时通知(含实时更新逻辑)
要实现动态倒计时效果,需要借助Notification Service Extension来实时更新通知内容,具体操作如下:
步骤1:添加Notification Service Extension
在Xcode中通过File > New > Target > Notification Service Extension添加扩展,用于后续实时更新倒计时文本。
步骤2:主App中创建初始通知
import UserNotifications func scheduleCountdownNotification(endTime: Date) { let content = UNMutableNotificationContent() content.title = "活动倒计时" content.body = "距离结束还有" content.categoryIdentifier = "CountdownNotification" content.interruptionLevel = .timeSensitive // 将结束时间存入userInfo,供扩展计算剩余时间 content.userInfo = ["endTime": endTime.timeIntervalSince1970] // 立即触发通知,后续由扩展循环更新内容 let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false) let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger) UNUserNotificationCenter.current().add(request) { error in if let error = error { print("通知创建失败: \(error.localizedDescription)") } } }
步骤3:扩展中实时更新倒计时
在Notification Service Extension的didReceive(_:withContentHandler:)方法中计算剩余时间并更新通知内容:
import UserNotifications class NotificationService: UNNotificationServiceExtension { var contentHandler: ((UNNotificationContent) -> Void)? var bestAttemptContent: UNMutableNotificationContent? override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { self.contentHandler = contentHandler bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) if let bestAttemptContent = bestAttemptContent, let endTimeInterval = bestAttemptContent.userInfo["endTime"] as? TimeInterval { let endTime = Date(timeIntervalSince1970: endTimeInterval) let currentTime = Date() let timeLeft = endTime.timeIntervalSince(currentTime) if timeLeft > 0 { let hours = Int(timeLeft) / 3600 let minutes = (Int(timeLeft) % 3600) / 60 let seconds = Int(timeLeft) % 60 bestAttemptContent.body = String(format: "距离结束还有 %02d:%02d:%02d", hours, minutes, seconds) // 每隔1秒重新调度通知,实现倒计时实时刷新 if timeLeft > 1 { let updateTrigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false) let updateRequest = UNNotificationRequest(identifier: request.identifier, content: bestAttemptContent, trigger: updateTrigger) UNUserNotificationCenter.current().add(updateRequest) } } else { bestAttemptContent.body = "活动已结束" } } contentHandler(bestAttemptContent ?? request.content) } override func serviceExtensionTimeWillExpire() { // 超时 fallback 处理 if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent { contentHandler(bestAttemptContent) } } }
3. 配置通知类别(可选)
如果需要给倒计时通知添加自定义操作按钮,可以提前配置通知类别:
func setupNotificationCategories() { let center = UNUserNotificationCenter.current() let category = UNNotificationCategory(identifier: "CountdownNotification", actions: [], intentIdentifiers: [], options: []) center.setNotificationCategories([category]) }
注意事项
- 该方案支持iOS 15及以上系统,需确保项目部署版本符合要求
- 通知扩展需单独配置签名和权限,避免打包出错
- 若使用远程推送,需在服务端推送的payload中携带倒计时结束时间,再由扩展处理更新
内容的提问来源于stack exchange,提问作者Ahmed Sokar
相关产品推荐
相关产品推荐

