I am having an issue with my push notification click. Everytime user clicks on the notifications, the app will crash instead of redirecting user to the specified page.
This part of the code is causing an error "Could not cast value of type 'appname.LaunchScreenController' to 'UINavigationController'"
:
let rootViewController = self.window!.rootViewController as! UINavigationController
And this code will cause fatal error: unexpectedly found nil while unwrapping an Optional value :
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
//receive the notifications
NotificationCenter.default.post(name: Notification.Name(rawValue: "MyNotificationType"), object: nil, userInfo: userInfo)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "NewsController") as! NewsViewController
let rootViewController = self.window!.rootViewController as! UINavigationController
rootViewController.pushViewController(vc, animated:true)
}
Thanks in advance
RootViewController is subclass of UIViewController not a UINavigationController You have to handle your null values
change to
let rootViewController = self.window!.rootViewController
I change the code to this and it works just fine now
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
NotificationCenter.default.post(name: Notification.Name(rawValue: "MyNotificationType"), object: nil, userInfo: userInfo)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "NewsController") as! NewsViewController
let nav = UINavigationController()
nav.pushViewController(vc, animated: true)
}
Related
I want to navigate to a specific viewcontroller when the I click on a push notification.
I have written this code in my didReceiveRemoteNotification method.
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "deals") as! FYIDealsVC
let naviVC:UINavigationController? = self.window?.rootViewController?.revealViewController().frontViewController as? UINavigationController
naviVC?.pushViewController(vc, animated: true)
}
But it's giving me this error which crashes the app.
fatal error: unexpectedly found nil while unwrapping an Optional value
There are many posts with navigation controller or just presenting the viewcontroller. But I want to navigate to the specific view with reveal.
Any help would be highly appreciated.
here is a another solution for this Try this:-
First Option :-
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier:
"deals") as! FYIDealsVC
// setup revelview controller and root with window
self.window?.rootViewController = //object of revelViewController
self.window?.makeKeyAndVisible()
Second option :-
// in Landing Screen from where you can easily navigate to the target
viewcontroller :-
in Landing VC:-
viewdidload:-
NotificationCenter.default.addObserver(self, selector:
#selector(self.navigationForNotification(notification:)), name:
NSNotification.Name(rawValue:PushNavigationIdentifier), object: nil)
// Selector Method :-
func navigationForNotification(notification:Notification) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier:
"deals") as! FYIDealsVC
self.navigationController?.pushViewController(vc, animated: true)
}
in appDelegate :-
func application(_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
NotificationCenter.default.post(name:
NSNotification.Name(PushNavigationIdentifier), object: userInfo)
}
Looks like error happens when you force unwrap FYIDealsVC.
Can you use
let vc = FYIDealsVC()
instead of
let vc = storyboard.instantiateViewController(withIdentifier: "deals") as! FYIDealsVC
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let auth: UIViewController =
storyBoard.instantiateViewController(withIdentifier: "Auth") as UIViewController
window?.rootViewController?.present(auth, animated: true, completion: nil)
return true
}
I get the error...
Warning: Attempt to present
on whose view is not in the
window hierarchy!
I presume the root controller has not been properly configured at this point in the app life cycle.
How do I do this? I want to avoid having the root controller having to check whether it needs to show the login screen.
You can do it like that:
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if Settings.appSettings.authToken != nil {
self.showMainController()
}
NotificationCenter.default.addObserver(forName: .authorizationOperationDidSuccess,
object: nil, queue: nil) { (notification) in
self.showMainController()
}
return true
}
private func showMainController() {
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let controller: UIViewController =
storyBoard.instantiateViewController(withIdentifier: "Main") as UIViewController
if self.window == nil {
self.window = UIWindow(frame: UIScreen.main.bounds)
}
self.window?.backgroundColor = UIColor.white
self.window?.rootViewController = controller
self.window?.makeKeyAndVisible()
}
private func showAuthorizationController() {
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let controller: UIViewController =
storyBoard.instantiateViewController(withIdentifier: "Auth") as UIViewController
if self.window == nil {
self.window = UIWindow(frame: UIScreen.main.bounds)
}
self.window?.backgroundColor = UIColor.white
self.window?.rootViewController = controller
self.window?.makeKeyAndVisible()
}
On successful login make
NotificationCenter.default.post(name: .authorizationOperationDidSuccess,
object: nil)
Make change here,
let auth: AuthVC = storyBoard.instantiateViewController(withIdentifier: "Auth") as AuthVC
// AuthVC is your_VC_name
Still facing issue, you can ask.
I got stuck specific view controller is not move when I tap on push notification alert when application is not open stage totally.
Here is my code:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
/*
fetch and add push notification data
*/
goAnotherVC()
}
func goAnotherVC() {
if (application.applicationState == UIApplicationState.active) {
/* active stage is working */
} else if (application.applicationState == UIApplicationState.inactive || application.applicationState == UIApplicationState.background) {
if (type == "1" || type == "2") {
let storyboard: UIStoryboard = UIStoryboard(name: "MyAppointments", bundle: nil)
let apptVC = storyboard.instantiateViewController(withIdentifier: "NotificationDetailViewController") as! NotificationDetailViewController
let navigationController = UINavigationController.init(rootViewController: apptVC)
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
} else if (type == "3") {
let storyboard: UIStoryboard = UIStoryboard(name: "MyAppointments", bundle: nil)
let apptVC = storyboard.instantiateViewController(withIdentifier: "NotificationDetailViewController") as! NotificationDetailViewController
let navigationController = UINavigationController.init(rootViewController: apptVC)
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
} else if (type == "4") {
let storyboard: UIStoryboard = UIStoryboard(name: "Enquiry", bundle: nil)
let enqVC = storyboard.instantiateViewController(withIdentifier: "EnquiryDetailViewController") as! EnquiryDetailViewController
let navigationController = UINavigationController.init(rootViewController: enqVC)
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
}
}
}
I can get notification and tap to move specific VC when application is active. Please help me what I am missing.
Swift 5
Simply, implement the following function which will be called when the user clicked on the notification.
In AppDelegate:
// This method is called when user clicked on the notification
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void)
{
// Do whatever you want when the user tapped on a notification
// If you are waiting for specific data from the notification
// (e.g., key: "target" and associated with "value"),
// you can capture it as follows then do the navigation:
// You may print `userInfo` dictionary, to see all data received with the notification.
let userInfo = response.notification.request.content.userInfo
if let targetValue = userInfo["target"] as? String, targetValue == "value"
{
coordinateToSomeVC()
}
completionHandler()
}
private func coordinateToSomeVC()
{
guard let window = UIApplication.shared.keyWindow else { return }
let storyboard = UIStoryboard(name: "YourStoryboard", bundle: nil)
let yourVC = storyboard.instantiateViewController(identifier: "yourVCIdentifier")
let navController = UINavigationController(rootViewController: yourVC)
navController.modalPresentationStyle = .fullScreen
// you can assign your vc directly or push it in navigation stack as follows:
window.rootViewController = navController
window.makeKeyAndVisible()
}
Note:
If you navigate to a specific controller based on the notification, you should care about how you will navigate back from this controller because there are no controllers in your stack right now. You must instantiate the controller you will back to. In my case, when the user clicked back, I instantiate the home controller and make it the app root again as the app will normally start.
When you app is in closed state you should check for launch option in
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { }
and call your API.
Example:
if let option = launchOptions {
let info = option[UIApplicationLaunchOptionsKey.remoteNotification]
if (info != nil) {
goAnotherVC()
}
}
Swift 5, iOS 13 -
Since iOS 13 "window" is available in SceneDelegate. But the didReceiveNotification method is still present in AppDelegate.
So you have to first access the window from SceneDelegate
let window = (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.window
Now You can set the rootViewController property of the window
window.rootViewController = viewControllerObject
window.makeKeyAndVisible()
I have my TabBarController as my initial view (storyboard identity Main) (Class UITabBarController)
Then a NavigationController (storyboard id = ViewController) (Class UINavigationController).
Then my ViewController (storyboard id = View) (Class ViewController)
Then my Details (storyboard id = StoryDetails) (Class Details)
I would like to navigate from AppDelegate.swift to the Details.swift uiviewcontroller.
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if let tabViewController = storyboard.instantiateViewControllerWithIdentifier("StoryDetails") as? UITabBarController {
window!.rootViewController!.presentViewController(tabViewController, animated: true, completion: nil)
}
But this is not working
Help would be really appreciated! (:
Also
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let detail = storyboard.instantiateViewControllerWithIdentifier("StoryDetails")
self.window?.rootViewController!.presentViewController(detail, animated: true, completion: nil)
This code brings up the view, but there is no navigation controller or tab bar controller
I'd like to navigate to a certain view controller after receiving a push notification. After navigation, the navigation stack should work as if the user got to the view manually.
The storyboard: http://www.xpos.nl/xpos/images/common/storyboard.png
In AppDelegate.swift I already have:
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
println("didReceiveRemoteNotification")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let destinationViewController = storyboard.instantiateViewControllerWithIdentifier("MessageViewController") as MessageViewController
let navigationController = self.window?.destinationViewController;
navigationController?.pushViewController(destinationViewController, animated: false, completion: nil)
}
But I get an error that destinationViewController is not part of window or if I correct that (trying other answers on stackoverflow), nothing happens.
The destinationViewController is not part of the window because it has not been added, just initialized. Based on the assumption that the navigationViewController is your rootViewController, push to your destinationViewController like this:
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
println("didReceiveRemoteNotification")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let destinationViewController = storyboard.instantiateViewControllerWithIdentifier("MessageViewController") as MessageViewController
let navigationController = self.window?.rootViewController as! UINavigationController
navigationController?.pushViewController(destinationViewController, animated: false, completion: nil)
}
Additionally: To push from "Bestellen" to "MessageViewController" and then pop to "Berichten", you need to push all the other viewControllers between those two, too. There is no built in function or algorithm to do that.
Try this
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
println("didReceiveRemoteNotification")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let destinationViewController = storyboard.instantiateViewControllerWithIdentifier("MessageViewController") as MessageViewController
self.window?.rootViewController?.presentViewController(destinationViewController, animated: True, completion:nil)
}