我有一个具有聊天功能的 SwiftUI 应用程序,它使用 Firebase 作为后端,并使用 Cloud Function 来侦听新的聊天消息并通知用户。当用户在相应的聊天室之一收到新的聊天消息时,云功能向登录用户的所有设备发送通知。为了导航,我创建了一个通知管理器,如果用户点击了通知,它可以帮助应用程序在应用程序的嵌套视图中导航。
一切正常,但是当用户在应用程序终止后点击通知时,导航不起作用。我猜这是因为在用户恢复之前导航被点击并且其属性被更改......?我试图寻找与 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()
}
}
}
}
通知管理器:
class NotificationManager: ObservableObject {
static let shared = NotificationManager()
@Published var pageToNavigationTo : Int?
@Published var recievedNotificationFromChatID: String?
}
ContentView 的 LightWeight 示例
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 = $0 else { return }
self.selection = notificationSelection // navigates to page InboxMessagesView
}
.onReceive(notificationManager.$recievedNotificationFromChatID) {
guard $0 != nil else { return }
self.activeChatID = $0 // navigates to the correct chat that is associated with the chatID when the user taps on a chat notification
}
}
}
好吧,我在 Swift 中发现了同样的问题,解决方案是将点击的通知的操作延迟一秒钟。感觉更像是一个黑客,我想确切地知道异步发生了什么,但它工作得很好。
解决方案如下:
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { // <- here!!
self.notificationManager?.pageToNavigationTo = 1
self.notificationManager?.recievedNotificationFromChatID = chatID
}
我最近面临同样的问题,看到你的解决方案有助于解决我的问题,因为你在
中有一个单身人士class NotificationManager: ObservableObject {
static let shared = NotificationManager()
...
}
与其延迟通知 1 秒(这可能会适得其反),不如在
AppDelegate
中使用单例(通知管理器可能尚未启动,这就是为什么延迟 1 秒可能会解决您的问题)
以某事结束
let notificationManager = self.notificationManager ?? NotificationManager.shared()
notificationManager.pageToNavigationTo = 1
notificationManager.recievedNotificationFromChatID = chatID
对我来说,做这样的事情就成功了!