我正在使用包含倒计时功能的 SwiftUI 重新开发适用于 iOS 的 android 应用程序。当倒计时结束时,应该通知用户倒计时结束。通知应该有点侵入性并且在不同的场景中工作,例如当用户没有主动使用手机时,当用户正在使用我的应用程序时,以及当用户正在使用另一个应用程序时。我决定使用本地通知来实现这一点,这是 android 的工作方法。 (如果这种方法完全错误,请告诉我什么是最佳做法)
但是,当用户当前使用我的应用程序时,我无法收到通知。通知仅显示在消息中心(所有通知排队的地方),但不会主动弹出。
到目前为止,这是我的代码:
用户被要求允许在我的 CountdownOrTimerSheet 结构中使用通知(从不同的 View 中调用作为 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
}
}
从上一个 View .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 的初始化中,通知最终被注册 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)")
}
}
如上所述,当用户在everyWhere 但我自己的应用程序时,通知会按预期显示。然而,TimerView 显示有关倒计时的信息,并且最好是用户设备上的事件 View 。因此,我需要能够在此处接收通知,也需要在我的应用程序中的其他任何地方接收通知,因为用户还可以在我的应用程序中的其他位置导航。如何实现?在 this example类似的事情已经完成,不幸的是不是用 swiftUI 而是用以前的通用语言编写的。我不明白这是如何完成的,或者如何完成这个。我在互联网上没有找到任何东西。我希望你能帮助我。
最佳答案
引用文档:
Scheduling and Handling Local Notifications
在关于当您的应用程序处于前台时处理通知的部分:
If a notification arrives while your app is in the foreground, you can silence that notification or tell the system to continue to display the notification interface. The system silences notifications for foreground apps by default, delivering the notification’s data directly to your app...
据此,您必须为
UNUserNotificationCenter
实现一个委托(delegate)。并调用completionHandler
告诉您希望如何处理通知。我建议你像这样,在
AppDelegate
上您为 UNUserNotificationCenter
分配代表因为文档说必须在应用程序完成启动之前完成(请注意文档说应该在应用程序完成启动之前设置委托(delegate)):// 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])
}
}
你可以告诉 SwiftUI 使用这个 AppDelegate
通过使用 UIApplicationDelegateAdaptor
在您的 App
上场景:@main
struct YourApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
关于ios - 在自己的应用程序/ View 中接收本地通知(或如何在 SwiftUI 中注册 UNUserNotificationCenterDelegate),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65782435/