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.
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.
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.
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.
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()
}
}