在自己的应用程序/视图中接收本地通知(或如何在SwiftUI中注册UNUserNotificationCenterDel



我正在用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])
}
}

您可以通过在App场景中使用UIApplicationDelegateAdaptor来告诉SwiftUI使用此AppDelegate

@main
struct YourApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}

创建代理类

import Foundation
import SwiftUI
class NotificationDelegate: NSObject , UNUserNotificationCenterDelegate{

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {

print("Notification tapped`")
//Do what you need to do here once the app is opened by tapping on the notification.
completionHandler()
}
}

将以下内容添加到您的应用程序文件

@main
struct myApp: App {

private var notificDelegate : NotificationDelegate = NotificationDelegate()

init(){
UNUserNotificationCenter.current().delegate = notificDelegate
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}

这种方法类似于苹果的Fruta:使用SwiftUI 构建功能丰富的应用程序

https://developer.apple.com/documentation/swiftui/fruta_building_a_feature-rich_app_with_swiftui

苹果以这种方式使用应用内购买


此类保存与Notification相关的所有代码。

class LocalNotificaitonCenter: NSObject, ObservableObject {
//  .....
}

@main应用程序结构中,将LocalNotificaitonCenter定义为@StateObject,并将其作为environmentObject传递给子视图

@main
struct YourApp: App {
@Environment(.scenePhase) private var scenePhase

@StateObject var localNotificaitonCenter = LocalNotificaitonCenter()

var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(localNotificaitonCenter)
}
}
}

就是这样!

相关内容

  • 没有找到相关文章

最新更新