在自己的应用程序/视图中接收本地通知(或如何在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()
        }
    }
}


以上是在自己的应用程序/视图中接收本地通知(或如何在SwiftUI中注册UNUserNotificationCenterDelegate)的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>