在自己的应用程序/视图中接收本地通知(或如何在SwiftUI中注册UNUserNotificationCenterDelegate)
我正在使用包含倒计时功能的 SwiftUI 重新开发适用于 iOS 的 Android 应用程序。当倒计时结束时,应该通知用户倒计时结束。通知应该有点侵入性,并在不同的场景下工作,例如当用户没有主动使用手机时,用户正在使用我的应用程序时以及用户正在使用另一个应用程序时。我决定使用本地通知来实现这一点,这是 android 的工作方法。(如果这种方法完全错误,请告诉我什么是最佳实践)
但是,当用户当前使用我的应用程序时,我无法接收通知。通知仅显示在消息中心(所有通知队列中),但不会主动弹出。
到目前为止,这是我的代码: 用户被要求允许在我的 CountdownOrTimerSheet 结构中使用通知(从不同的视图中作为 actionSheet 调用):
/**
asks for permission to show notifications, (only once) if user denied there is no information about this , it is just not grantedand the user then has to go to settings to allow notifications
if permission is granted it returns true
*/
func askForNotificationPermission(userGrantedPremission: @escaping (Bool)->())
{
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { success, error in
if success {
userGrantedPremission(true)
} else if let error = error {
userGrantedPremission(false)
}
}
}
仅当用户允许通知权限时,才会调用我的 TimerView 结构
askForNotificationPermission() { (success) -> () in
if success
{
// permission granted
...
// passing information about the countdown duration and others..
...
userConfirmedSelection = true // indicates to calling view onDismiss that user wishes to start a countdown
showSheetView = false // closes this actionSheet
}
else
{
// permission denied
showNotificationPermissionIsNeededButton = true
}
}
从上一个视图
.sheet(isPresented: $showCountDownOrTimerSheet, onDismiss: {
// what to do when sheet was dismissed
if userConfirmedChange
{
// go to timer activity and pass startTimerInformation to activity
programmaticNavigationDestination = .timer
}
}) {
CountdownOrTimerSheet(startTimerInformation: Binding($startTimerInformation)!, showSheetView: $showCountDownOrTimerSheet, userConfirmedSelection: $userConfirmedChange)
}
...
NavigationLink("timer", destination:
TimerView(...),
tag: .timer, selection: $programmaticNavigationDestination)
.frame(width: 0, height: 0)
在我的 TimerView 的 init 中,通知终于注册了
self.endDate = Date().fromTimeMillis(timeMillis: timerServiceRelevantVars.endOfCountDownInMilliseconds_date)
// set a countdown Finished notification to the end of countdown
let calendar = Calendar.current
let notificationComponents = calendar.dateComponents([.hour, .minute, .second], from: endDate)
let trigger = UNCalendarNotificationTrigger(dateMatching: notificationComponents, repeats: false)
let content = UNMutableNotificationContent()
content.title = "Countdown Finished"
content.subtitle = "the countdown finished"
content.sound = UNNotificationSound.defaultCritical
// choose a random identifier
let request2 = UNNotificationRequest(identifier: "endCountdown", content: content, trigger: trigger)
// add the notification request
UNUserNotificationCenter.current().add(request2)
{
(error) in
if let error = error
{
print("Uh oh! We had an error: (error)")
}
}
如上所述,当用户无处不在但我自己的应用程序时,通知会按预期显示。但是 TimerView 显示有关倒计时的信息,并且最好是用户设备上的活动视图。因此,我需要能够在此处接收通知,而且还需要在我的应用程序中的其他任何地方接收通知,因为用户还可以在我的应用程序中的其他地方导航。如何做到这一点?
在这个例子中已经完成了类似的事情,不幸的是不是用 swiftUI 编写的,而是用以前的通用语言编写的。我不明白这是如何完成的,或者如何完成这个..我在互联网上没有找到任何关于这个的东西..我希望你能帮助我。
回答
参考文档:
调度和处理本地通知
关于当你的应用程序在前台时处理通知部分:
如果在您的应用程序处于前台时收到通知,您可以将该通知静音或告诉系统继续显示通知界面。默认情况下,系统会静音前台应用的通知,将通知数据直接传送到您的应用...
根据这一点,您必须实现一个委托UNUserNotificationCenter并调用completionHandler告诉您希望如何处理通知。我建议你这样做,因为文档说它必须在应用程序完成启动之前完成(请注意文档说应该在应用程序完成启动之前设置AppDelegate委托),UNUserNotificationCenter所以在你分配委托的地方:
// AppDelegate.swift
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
UNUserNotificationCenter.current().delegate = self
return true
}
}
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
// Here we actually handle the notification
print("Notification received with identifier (notification.request.identifier)")
// So we call the completionHandler telling that the notification should display a banner and play the notification sound - this will happen while the app is in foreground
completionHandler([.banner, .sound])
}
}
您可以AppDelegate通过UIApplicationDelegateAdaptor在您的App场景中使用 来告诉 SwiftUI 使用它:
@main
struct YourApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}