2 years ago

#63165

test-img

John Sorensen

Programmatic Navigation after opening notification SwiftUI

So I have a bunch of UIKit code to enable my iOS app to receive notifications. How do I programmatically navigate upon a user opening a notification?

Code to Receive Notifications:

class AppDelegate: NSObject, UIApplicationDelegate {
    let gcmMessageIDKey = "gcm.message_id"
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
    
    
        FirebaseApp.configure()
    
        Messaging.messaging().delegate = self
    
        if #available(iOS 10.0, *) {
          // For iOS 10 display notification (sent via APNS)
          UNUserNotificationCenter.current().delegate = self

          let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
          UNUserNotificationCenter.current().requestAuthorization(
            options: authOptions,
            completionHandler: { _, _ in }
          )
        } else {
          let settings: UIUserNotificationSettings =
            UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
          application.registerUserNotificationSettings(settings)
        }

        application.registerForRemoteNotifications()
    
        return true
    }

    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    
        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
        }
    
        print(userInfo)
    
        completionHandler(UIBackgroundFetchResult.newData)
    }

    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
    
    }

    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceTokenL: Data) {
    
    }
}

extension AppDelegate: MessagingDelegate {

    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?){
        print("Firebase Registration Token: \(String(describing: fcmToken))")
    
        let dataDict: [String: String] = ["token": fcmToken ?? ""]
        print(dataDict)
    
        // store here
    }
}

extension AppDelegate: UNUserNotificationCenterDelegate {
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping 
(UNNotificationPresentationOptions) -> Void) {
        let userInfo = notification.request.content.userInfo
    
        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
        }
    
        print(userInfo)
    
        completionHandler([[.banner, .badge, .sound]])
    }

    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: \(messageID)")
        }
    }
}

My app delegate is instantiated here:

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

My ContentView is what has the navigation functionality:

struct ContentView: View {
    @State var selectedTab: MenuTab = .first
    var body: some View {
        NavigationView {
            VStack {
                if selectedTab == .first {
                    Text("First Screen")
                        .frame(maxHeight: .infinity)
                } else if selectedTab == .second {
                    Text("Second Screen")
                        .frame(maxHeight: .infinity)
                } else if selectedTab == .third {
                    Text("Third Screen")
                        .frame(maxHeight: .infinity)
                }
            
                TabPicker(selectedTab: $selectedTab)
            }
        }
    }
}

enum MenuTab {
    case first
    case second
    case third
}

struct TabPicker: View {
    @Binding var selectedTab: MenuTab
    var body: some View {
        HStack {
            Spacer()
            Text("1")
                .fontWeight( selectedTab == .first ? .bold: .light)
                .onTapGesture { selectedTab = .first }
            Spacer()
            Text("2")
                .fontWeight( selectedTab == .second ? .bold: .light)
                .onTapGesture { selectedTab = .second }
            Spacer()
            Text("3")
                .fontWeight( selectedTab == .third ? .bold: .light)
                .onTapGesture { selectedTab = .third }
            Spacer()
        }
    }
}

I assume that something in the UIKit code is triggered whenever a user opens a notification--how do pass that information to my ContentView? We can imagine that, depending on the type of notification, we might want the app to automatically navigate to any one of the three screens I have in this MRP.

P.S. (I just realized that technically I'm not using the NavigationView)

swiftui

notifications

navigation

0 Answers

Your Answer

Accepted video resources