I am trying to get the 3d touch quick action to work, I have this code below.
I do get a print saying it was pressed but it doesn't go to the view controller I want.
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: #escaping (Bool) -> Void) {
if shortcutItem.type == "LiveFeed" {
print("Tony: We got to live view")
guard let navVC = window?.rootViewController as? UINavigationController else { return }
let storyBoard: UIStoryboard = UIStoryboard(name: "LiveFeed", bundle: nil)
if #available(iOS 11.0, *) {
let composeViewController = storyBoard.instantiateViewController(withIdentifier: "LiveFeedMain") as! LiveFeedMain
navVC.pushViewController(composeViewController, animated: false)
} else {
// Fallback on earlier versions
}
}
}
I have this in the appDelegate
Related
I want to redirect to particular screen once user tap the push notification. and for that i have tried below code and the view presented successfully but i'm unable to use the app navigation flow after setting the particular view as RootViewController.
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
//let alertMsg = (userInfo["aps"] as! NSDictionary)["alert"] as! NSDictionary
//let payload = userInfo["sendbird"] as! NSDictionary
//APS DATA
if let apsData = userInfo["aps"] as? Dictionary<String, Any> {
print(apsData)
}
//USER DATA
if let userData = userInfo["user_details"] as? Dictionary<String, Any> {
print(userData)
}
//NOTIFICATION DATA
if let notificationData = userInfo["notification_details"] as? Dictionary<String, Any> {
print(notificationData)
let nNotificationType = notificationData["notification_type"] as! Int
let nNotificationID = notificationData["notification_id"] as! Int
}
let storyBoard : UIStoryboard = UIStoryboard(name: "Group", bundle:nil)
if Device.IS_IPHONE_X {
let controller = storyBoard.instantiateViewController(withIdentifier: "GroupInfoViewController_iPhoneX") as! GroupInfoViewController
let navController = UINavigationController.init(rootViewController: controller)
}
else {
let controller = storyBoard.instantiateViewController(withIdentifier: "GroupInfoViewController_iPhone8") as! GroupInfoViewController
let navController = UINavigationController.init(rootViewController: controller)
}
// Your custom way to parse data
completionHandler(UIBackgroundFetchResult.newData)
}
Please guide me how can i use the normal app navigation after move to particular ViewController on notification tap. same like android app.
Please guide me
After some R&D, i found the working solution to move to particular controller on notification tap over PRESENTED or PUSHED ViewController.
Here is the working code.
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { // change your delay here
let storyboard = UIStoryboard(name: "Group", bundle: nil)
if Device.IS_IPHONE_X {
let vc = storyboard.instantiateViewController(withIdentifier: "GroupInfoViewController_iPhoneX") as! GroupInfoViewController
vc.nNotificationID = notificationID
if let topVC = UIApplication.getTopViewController() {
topVC.navigationController?.pushViewController(vc, animated: false)
}
}
else {
let vc = storyboard.instantiateViewController(withIdentifier: "GroupInfoViewController_iPhone8") as! GroupInfoViewController
vc.nNotificationID = notificationID
if let topVC = UIApplication.getTopViewController() {
topVC.navigationController?.pushViewController(vc, animated: false)
}
}
}
}
Extension
public extension UIApplication {
class func getTopViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return getTopViewController(base: nav.visibleViewController)
} else if let tab = base as? UITabBarController, let selected = tab.selectedViewController {
return getTopViewController(base: selected)
} else if let presented = base?.presentedViewController {
return getTopViewController(base: presented)
}
return base
}
}
Create a function like this:
func handleNotification(userInfo: [String:Any]) {
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
if let mainNav = AppDelegate.shared.window?.rootViewController as? UINavigationController {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "YourVC") as! YourVC
mainNav.pushViewController(vc, animated: false)
}
}
}
You can also pass information in userInfo If you want to perform certain operations or just removed that parameter.
And call this function in your this method
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
print("APNs received with: \(userInfo)")
self.handleNotification(userInfo: userInfo as! [String : Any])
}
let vc = storyboard.instantiateViewController(withIdentifier: "YourVC") as!
YourVC
mainNav.pushViewController(vc, animated: false)
use push or present to pass one view controller to another
I am trying to add 3D touch quick action in my app. I have two viewContollers embedded in navigationContoller. When the user press on the 3D action, it should take them to the add events viewController. But i am getting this error
could not cast value of type 'Morning_Star_2.AddEventsViewController' (0x1000a2260) to 'UINavigationController' (0x1a79cd360).
2017-05-02 02:51:36.220324-0400 Morning Star 2[3731:895126] Could not cast value of type 'Morning_Star_2.AddEventsViewController' (0x1000a2260) to 'UINavigationController' (0x1a79cd360).
Here is my code
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: #escaping (Bool) -> Void) {
if shortcutItem.type == "com.krp.addEvent" {
let sb = UIStoryboard(name: "Main", bundle: nil)
let addEventVC = sb.instantiateViewController(withIdentifier: "addEventVC") as! UINavigationController
self.window?.rootViewController?.present(addEventVC, animated: true, completion: nil)
}
}
I tried changing as! UINavigationController to as! AddEventsViewController. It works, but then it won't show the navigation bar on the top on my add viewController as it normally would if you open the app normally.
Here is my main.storyboard
You shouldn't cast AddEventsViewController to UINavigationController, because it isn't UINavigationController, is just subclass of UIViewController. But as I see, your rootViewController is. So you need to cast it to UINavigationController, and then push your AddEventsViewController, instead present, and you will see NavigationBar
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: #escaping (Bool) -> Void) {
if shortcutItem.type == "com.krp.addEvent" {
let sb = UIStoryboard(name: "Main", bundle: nil)
let addEventVC = sb.instantiateViewController(withIdentifier: "addEventVC") as! AddEventsViewController
if let navigationController = window?.rootViewController as? UINavigationController {
navigationController.pushViewController(addEventVC, animated: true)
}
}
}
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 a 3D Force Touch Action that I set up in my Info.plist. Now I want that when the 3D Action is running it presents a view controller that I gave a Storyboard ID and I need to do this in the AppDelegate.
I used the performActionForShortCutItem function.
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: #escaping (Bool) -> Void) {
if let tabVC = self.window?.rootViewController as? UITabBarController {
if shortcutItem.type == "Hausaufgaben" {
tabVC.selectedIndex = 1
tabVC.performSegue(withIdentifier: "gotoHausaufgaben", sender: nil)
}
}
}
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: #escaping (Bool) -> Void) {
if shortcutItem.type == "Hausaufgaben" {
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "YOUR PAGE Identifier")
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
}
}
I got a 3d touch function in my app delegate for the shortcutitems and it has to instantiate a viewcontroller when 3d touch item clicked from the iphone.
Here is the code:
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: #escaping (Bool) -> Void) {
if shortcutItem.type == "com.kevinvugts.addStuf" {
let sb = UIStoryboard(name: "Main", bundle: nil)
let exerciseVC = sb.instantiateViewController(withIdentifier: "exerciseVC") as! exerciseVC
let root = UIApplication.shared.keyWindow?.rootViewController
root?.present(exerciseVC, animated: false, completion: { () -> Void in
completionHandler(true)
})
}
}
This code results in this warning/error:
Warning: Attempt to present <ActiveRest.exerciseVC: 0x131d39320> on <ActiveRest.ViewController: 0x131d0e470> whose view is not in the window hierarchy!
Has this anything to do with delay?
Thanks for any help!
Kind Regards.
view is not in the window hierarchy that means your view of your viewcontroller is not loaded in memory still. so you are unable to present viewcontroller on it. you should have to present viewcontroller from viewDidAppear of your viewcontroller (I mean from your rootviewController).
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: #escaping (Bool) -> Void) {
if shortcutItem.type == "com.kevinvugts.addStuf" {
let sb = UIStoryboard(name: "Main", bundle: nil)
let exerciseVC = sb.instantiateViewController(withIdentifier: "exerciseVC") as! exerciseVC
window?.rootViewController?.addChildViewController(exerciseVC)
}
}
I made this change and everything works fine.