SwiftUI 处理在终止状态下点击的推送通知
SwiftUI handle push notifications tapped in a terminated state
我有一个带有聊天功能的 SwiftUI 应用程序,它使用 Firebase 作为其后端和 Cloud Function 来侦听新的聊天消息并通知用户。当用户在相应的聊天室之一中收到新的聊天消息时,Cloud Function 会向登录用户的所有设备发送通知。为了导航,我创建了一个 NotificationManager,如果用户点击了通知,它可以帮助应用程序在应用程序的嵌套视图中导航。
一切正常,但是当用户在应用程序终止后点击通知时,导航不起作用。我想这是因为在用户恢复之前导航被点击并且它的属性被更改......?我试图寻找与 UIKit 相关的解决方案(因为我没有找到任何与 SwiftUI 相关的解决方案),但还没有找到合适的解决方案。
在我的 AppDelegate 上面:
weak var notificationManager: NotificationManager?
用户点击通知:
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID from userNotificationCenter didReceive: \(messageID)")
}
print("*** NotificationInfo: \(userInfo) ***")
let info = userInfo as NSDictionary
guard let chatID = info.value(forKey: "chatID") as? String else { return } // retrieving the ChatID from notification payload
// Navigate to the room of the chatID when chat notification is tapped
notificationManager?.pageToNavigationTo = 1 // navigate to messages view
notificationManager?.recievedNotificationFromChatID = chatID // navigate to correct chat
completionHandler()
}
生命周期:
@main
struct VitaliiApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
@StateObject var session = SessionStore()
let notificationManager = NotificationManager()
func setUpdNotificationManager() {
appDelegate.notificationManager = notificationManager
}
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(session)
.environmentObject(notificationManager)
.onAppear {
setUpdNotificationManager()
}
}
}
}
NotificationManager:
class NotificationManager: ObservableObject {
static let shared = NotificationManager()
@Published var pageToNavigationTo : Int?
@Published var recievedNotificationFromChatID: String?
}
ContentView 的轻量级示例
struct ContentView: View {
@State var selection: Int = 0
@EnvironmentObject var session: SessionStore
@State var activeChatID: String?
let tabBarImageNames = ["person.3", "message", "person"]
@EnvironmentObject private var notificationManager: NotificationManager
var body: some View {
ZStack {
Color.black
.ignoresSafeArea()
VStack {
ZStack {
switch selection {
case 0:
NavigationView {
HomeView()
}
case 1:
NavigationView {
InboxMessagesView(user: session.userSession, activeChatID: $activeChatID)
}
.accentColor(.white)
default:
NavigationView {
ProfileView(session: session.userSession)
}
}
}
Spacer()
HStack {
ForEach(0..<3) { num in
Button {
selection = num
} label: {
Spacer()
Image(systemName: tabBarImageNames[num])
.padding(.top, 10)
.font(.system(size: 20, weight: .medium))
.foregroundColor(selection == num ? .red : .white.opacity(0.7))
Spacer()
}
}
}
}
}
.ignoresSafeArea(.keyboard, edges: .bottom)
.onReceive(notificationManager.$pageToNavigationTo) {
guard let notificationSelection = [=14=] else { return }
self.selection = notificationSelection // navigates to page InboxMessagesView
}
.onReceive(notificationManager.$recievedNotificationFromChatID) {
guard [=14=] != nil else { return }
self.activeChatID = [=14=] // navigates to the correct chat that is associated with the chatID when the user taps on a chat notification
}
}
}
好吧,我在Swift中发现了同样的问题,解决方法是将点击通知的动作延迟一秒。感觉更像是 hack,我想确切地知道异步发生了什么,但它工作得很好。
解决方法如下:
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { // <- here!!
self.notificationManager?.pageToNavigationTo = 1
self.notificationManager?.recievedNotificationFromChatID = chatID
}
我有一个带有聊天功能的 SwiftUI 应用程序,它使用 Firebase 作为其后端和 Cloud Function 来侦听新的聊天消息并通知用户。当用户在相应的聊天室之一中收到新的聊天消息时,Cloud Function 会向登录用户的所有设备发送通知。为了导航,我创建了一个 NotificationManager,如果用户点击了通知,它可以帮助应用程序在应用程序的嵌套视图中导航。
一切正常,但是当用户在应用程序终止后点击通知时,导航不起作用。我想这是因为在用户恢复之前导航被点击并且它的属性被更改......?我试图寻找与 UIKit 相关的解决方案(因为我没有找到任何与 SwiftUI 相关的解决方案),但还没有找到合适的解决方案。
在我的 AppDelegate 上面:
weak var notificationManager: NotificationManager?
用户点击通知:
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID from userNotificationCenter didReceive: \(messageID)")
}
print("*** NotificationInfo: \(userInfo) ***")
let info = userInfo as NSDictionary
guard let chatID = info.value(forKey: "chatID") as? String else { return } // retrieving the ChatID from notification payload
// Navigate to the room of the chatID when chat notification is tapped
notificationManager?.pageToNavigationTo = 1 // navigate to messages view
notificationManager?.recievedNotificationFromChatID = chatID // navigate to correct chat
completionHandler()
}
生命周期:
@main
struct VitaliiApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
@StateObject var session = SessionStore()
let notificationManager = NotificationManager()
func setUpdNotificationManager() {
appDelegate.notificationManager = notificationManager
}
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(session)
.environmentObject(notificationManager)
.onAppear {
setUpdNotificationManager()
}
}
}
}
NotificationManager:
class NotificationManager: ObservableObject {
static let shared = NotificationManager()
@Published var pageToNavigationTo : Int?
@Published var recievedNotificationFromChatID: String?
}
ContentView 的轻量级示例
struct ContentView: View {
@State var selection: Int = 0
@EnvironmentObject var session: SessionStore
@State var activeChatID: String?
let tabBarImageNames = ["person.3", "message", "person"]
@EnvironmentObject private var notificationManager: NotificationManager
var body: some View {
ZStack {
Color.black
.ignoresSafeArea()
VStack {
ZStack {
switch selection {
case 0:
NavigationView {
HomeView()
}
case 1:
NavigationView {
InboxMessagesView(user: session.userSession, activeChatID: $activeChatID)
}
.accentColor(.white)
default:
NavigationView {
ProfileView(session: session.userSession)
}
}
}
Spacer()
HStack {
ForEach(0..<3) { num in
Button {
selection = num
} label: {
Spacer()
Image(systemName: tabBarImageNames[num])
.padding(.top, 10)
.font(.system(size: 20, weight: .medium))
.foregroundColor(selection == num ? .red : .white.opacity(0.7))
Spacer()
}
}
}
}
}
.ignoresSafeArea(.keyboard, edges: .bottom)
.onReceive(notificationManager.$pageToNavigationTo) {
guard let notificationSelection = [=14=] else { return }
self.selection = notificationSelection // navigates to page InboxMessagesView
}
.onReceive(notificationManager.$recievedNotificationFromChatID) {
guard [=14=] != nil else { return }
self.activeChatID = [=14=] // navigates to the correct chat that is associated with the chatID when the user taps on a chat notification
}
}
}
好吧,我在Swift中发现了同样的问题,解决方法是将点击通知的动作延迟一秒。感觉更像是 hack,我想确切地知道异步发生了什么,但它工作得很好。
解决方法如下:
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { // <- here!!
self.notificationManager?.pageToNavigationTo = 1
self.notificationManager?.recievedNotificationFromChatID = chatID
}