This worked well for deep navigation after the user tapped a chat notification. The chat notification comes from Firebase so I have to retrieve the ChatID from the notification to know which one I have to open.
With that in mind, I also know that the selected tab on the tabBar for the messages is the Int value of 1.
Now I can create a manager that works as a observed singelton object that listens to each notification that a user has tapped.
Above in AppDelegate:
weak var notificationManager: NotificationManager?
User notification tapped:
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()
}
// MARK: - SwiftUI Lifecycle
@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()
}
}
}
}
The NotificationManager:
class NotificationManager: ObservableObject {
static let shared = NotificationManager()
@Published var pageToNavigationTo : Int?
@Published var recievedNotificationFromChatID: String?
}
My ContentView with onRecieve() that listens to the NotificationManager and navigates to my InboxMessageView if a notification is tapped.
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
}
}
}
In the InboxMessagesView I just have a ForEach loop with all the current user chats in a NavigationLink where each link is tagged with their corresponding chatID. It navigates by itself to the right chat if the notification is tapped. I can add the code for that View too if you want to.