Notifications Landing Page

I have an app and I have notifications set up through firebase. The notifications come in correctly, but when you click on them it opens the app. I would like to have it set up so when the notification is clicked on it lands on a specific viewcontroller within my app. Is there a tutorial on how to make this happen?

Welcome to the community!

I can’t remember if Chris has a specific tutorial on this. You’ll have to start looking at responding to the SceneDelegate and/or the app lifecycle (where you create an app and there’s no AppDelegate or SceneDelegate)

I am still new to coding and trying to learn. I have spent the past 3 weeks googling and searching youtube for answers and I simply can’t figure it out. If anyone could PLEASE point me in the right direction I would be GREATLY appreciative!

I have an app and I have firebase cloud messaging set up and working perfectly. When the notification is received and it is onclicked it opens my app. But I would like to have it open a certain viewcontroller within my app instead of going to the first screen.

I have researched dynamic links and emeded links and I just can’t figure it out. Maybe I’m not searching for the right words or something? I did another post and someone said they didn’t think Chris had a tutorial on this?

Any help, suggestions or direction would be fantastic. Thank you.

Try this

Also next time you could’ve just commented on the post that you already made about this topic, about why/why not some solutions didn’t work

I believe you can merge these topics together, I’d suggest doing that

Wow, so sorry I didn’t do it the way you wanted. I’m not sure how to do it, so feel free to delete the post. I’ll try to find another place to ask my questions. Thanks for you hospitality.

It’s OK. The two posts have already been merged by myself a few minutes ago so you don’t need to do anything else. :+1:

I read that entire post (it was posted in 2018) those variables don’t work in IOS13… so I am back to square one. I searched for ‘resonding to scenedelegate’ for ‘app lifecycle’… i’ve learned a lot, but none of those go back to my question.

this link, the first one I linked, what do you mean? What doesn’t work, specifically? The post below shows how to access the window in SceneDelegate if that’s what you’re referring to

It looks like this is the proper function called after receiving a notification.
You can check this by just printing something here and seeing if the app shows your print statement

Also here’s another post, this blog has helped me before

It might help if you provided some code showing what you have tried that doesn’t work. It’s kind of hard to help when we only have vague descriptions of what you’re doing and a statement that the given suggestions “don’t work” without any details.

1 Like

import Firebase
import FirebaseMessaging
import UserNotifications
import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate, MessagingDelegate, UNUserNotificationCenterDelegate {

  // This function will be called right after user tap on the notification
  func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
      
      
      

      


  
      
      
      
      
    // tell the app that we have finished processing the user’s action / response
    completionHandler()
  }


func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    FirebaseApp.configure()
    
    Messaging.messaging().delegate = self
    UNUserNotificationCenter.current().delegate = self
    UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { success, _ in guard success else {
        return
    }
    print("Success in APNS registry")
    }
    
    application.registerForRemoteNotifications()
    
    // Override point for customization after application launch.
    return true
}

func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
    messaging.token { token, _ in
        guard let token = token else {
            return
        }
        print("Token: \(token)")
    }
}

// MARK: UISceneSession Lifecycle

func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
    // Called when a new scene session is being created.
    // Use this method to select a configuration to create the new scene with.
    return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}

func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
    // Called when the user discards a scene session.
    // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
    // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
  
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    guard let rootViewController = (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.window?.rootViewController else {
        return
    }
    if let convsersationVC = storyboard?.instantiateViewController(withIdentifier: "notificationViewController") as? notificationViewController,
       let tabBarController = rootViewController as? UITabBarController,
       let navController = tabBarController.selectedViewController as? UINavigationController {
        
        convsersationVC.senderDisplayName = response.notification.request.content.title
        navController.pushViewController(convsersationVC, animated: true)
    }
    completionHandler()
}

}

This is the second way I tried it. The other way worked without errors, but wouldn’t load the vc, just opened the app

private func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
      
        // the root view controller
        guard var rootViewController = (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.window?.rootViewController else {
        return
    }
    
    let storyboard = UIStoryboard(name: "Main", bundle: nil)

    // instantiate the view controller from storyboard
    if  let notificationVC = storyboard.instantiateViewController(withIdentifier: "notificationViewController") as? notificationViewController {

        // set the view controller as root
        rootViewController = notificationVC
    }
    
    // tell the app that we have finished processing the user’s action / response
    completionHandler()

}

Each read says to use the first line “private func…” but it keeps giving me the “Invalid redeclaration of ‘userNotificationCenter(_:didReceive:withCompletionHandler:)’” error. I don’t understand why?

Redeclaration would mean you’re trying to write a function but it already exists. It’s like in a view controller if you tried to make your own viewDidLoad function, it would say “invalid redeclaration” because there’s already a default Apple version of this function

import Firebase
import FirebaseMessaging
import UserNotifications
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate, MessagingDelegate, UNUserNotificationCenterDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) → Bool {
FirebaseApp.configure()
Messaging.messaging().delegate = self
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { success, _ in guard success else {
return
}
print(“Success in APNS registry”)
}
application.registerForRemoteNotifications()
return true
}
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
messaging.token { token, _ in
guard let token = token else {
return
}
print(“Token: (token)”)
}
//ONTAP
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () → Void) {
guard var rootViewController = (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.window?.rootViewController else {
return
}
let storyboard = UIStoryboard(name: “Main”, bundle: nil)
if let myVC = storyboard.instantiateViewController(withIdentifier: “tommyViewController”) as? tommyViewController {
rootViewController = myVC
}
completionHandler()
}
}
}

I have read your links extensively and have come down to this code(my entire AppDelegate). I am getting no errors, but when I send push notification the app still opens to the opening screen and not to the ‘tommyViewController’.

If you set a breakpoint here does myVC have a value?

Also a quick tip on formatting
To format the code nicely, place 3 back-ticks ``` on the line above your code and 3 back-ticks ``` on the line below your code. The 3 back-ticks must be the ONLY characters on the line. The back-tick character is located on the same keyboard key as the tilde character ~ (which is located below the Esc key). You can also highlight an entire code block and click the </> button on the toolbar to wrap the block for you.

@Rilose

I pasted your code into AppDelegate in a test UIKit app that I created. One problem I noticed is that you have a function defined within another function and I don’t think that is helping you.

See if this amended code helps.

class AppDelegate: UIResponder, UIApplicationDelegate, MessagingDelegate, UNUserNotificationCenterDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        FirebaseApp.configure()
        Messaging.messaging().delegate = self
        UNUserNotificationCenter.current().delegate = self
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { success, _ in guard success else {
            return
        }
            print("Success in APNS registry")
        }
        application.registerForRemoteNotifications()
        return true
    }

    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
        messaging.token { token, _ in
            guard let token = token else {
                return
            }
            print("Token: (token)")
        }

    }

    //ONTAP
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                didReceive response: UNNotificationResponse,
                                withCompletionHandler completionHandler: @escaping () -> Void) {
        guard var rootViewController = (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.window?.rootViewController else {
            return
        }
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        if let myVC = storyboard.instantiateViewController(withIdentifier: "tommyViewController") as? tommyViewController {
            rootViewController = myVC
        }
        completionHandler()
    }
}

Without access to your entire application I am really shooting in the dark so let us now how this goes.

@Rilose

Can I ask what tutorial you have been following to set this messaging process up?

I’m wondering if you have had a look at this tutorial from Ray Wenderlich.

It seems that some of the things you are trying to implement in your AppDelegate are somewhat similar to the tutorial that Ray has written. Perhaps it may be of help to you.

I used the link that @mikaelacaron shared. They said that code wouldn’t work with 13.0 or below so I went to the link they provided Here and used it as reference for what I was doing.

import Firebase
import FirebaseMessaging
import UserNotifications
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate, MessagingDelegate, UNUserNotificationCenterDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        FirebaseApp.configure()
        Messaging.messaging().delegate = self
            UNUserNotificationCenter.current().delegate = self
            UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { success, _ in guard success else {
                return
            }
            print("Success in APNS registry")
            }
        application.registerForRemoteNotifications()
        return true
    }
    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
        messaging.token { token, _ in
            guard let token = token else {
                return
            }
            print("Tokens: \(token)")
            print("userDisplayName:")
        }
//ONTAP

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

            if let window = (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.window {
                if let rootViewController = (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.window?.rootViewController {
                    if let tabBarController = rootViewController as? MainViewController {
                        window.rootViewController = tabBarController
                        window.makeKeyAndVisible()
                    }
                } else {
                    let tabBarController = UIStoryboard(name: "main", bundle: .main).instantiateViewController(identifier: "tommyViewController") as? tommyViewController
                    window.rootViewController = tabBarController
                    window.makeKeyAndVisible()
                }
            }
            completionHandler()
        }
}
}

Found THIS PAGE and tried this code. Again, no errors, but won’t land on the right vc

The problem with that code is that the function userNotificationsCenter(…) is inside the function messaging(…)

It needs to be below the function messaging() like this so that the function is “visible”:

import Firebase
import FirebaseMessaging
import UserNotifications
import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate, MessagingDelegate, UNUserNotificationCenterDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        FirebaseApp.configure()
        Messaging.messaging().delegate = self
        UNUserNotificationCenter.current().delegate = self
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { success, _ in guard success else {
            return
        }
            print("Success in APNS registry")
        }
        application.registerForRemoteNotifications()
        return true
    }
    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
        messaging.token { token, _ in
            guard let token = token else {
                return
            }
            print("Tokens: \(token)")
            print("userDisplayName:")
        }

    }

    //ONTAP

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

        if let window = (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.window {
            if let rootViewController = (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.window?.rootViewController {
                if let tabBarController = rootViewController as? MainViewController {
                    window.rootViewController = tabBarController
                    window.makeKeyAndVisible()
                }
            } else {
                let tabBarController = UIStoryboard(name: "main", bundle: .main).instantiateViewController(identifier: "tommyViewController") as? tommyViewController
                window.rootViewController = tabBarController
                window.makeKeyAndVisible()
            }
        }
        completionHandler()
    }
}