When my App opens from background by user's response to notifications, I'll direct them to the respective screen depending on the notification. The process involved replacing the window.rootViewController in AppDelegate.
The following is my codes handling the notification:
if application.applicationState == .background {
let info = userInfo["custom"] as! [AnyHashable : Any]
let a = info["a"] as! [AnyHashable : Any]
switch a["notificationType"] as! Int {
case 1:
let newVC = StoryBoardInstantiation.instantiateNewContentViewController(true)
let leftVC = StoryBoardInstantiation.instantiateLeftPanelVC()
let sideMenu = SSASideMenu(contentViewController: UINavigationController(rootViewController: newVC), leftMenuViewController: leftVC)
self.window?.rootViewController = sideMenu
}
}
Afterwards when the user navigates around the app, whenever there are animated changes to view controllers, the original ViewController(the one replaced in the codes) will be visible in the background.
How do I remove the previous rootViewController that is already replaced?
Related
For the new user I have several onboarding screens (all of them are in the same OnboardViewController). If user is successfully registered, I'd change the root controller of my app from OnboardViewController to PreLoadViewController:
let mcVC = PreLoadController()
appDelegateTemp.window?.rootViewController = mcVC
I'm using this controller to display progress of the content loading. After the content is loaded, I'm changing the root controller once again:
if let appDelegateTemp = UIApplication.shared.delegate as? AppDelegate {
let mcVC = MainViewController()
let navy = UINavigationController(rootViewController: mcVC)
appDelegateTemp.window?.rootViewController = navy
}
It works, but I have a very strange bug. When I'm trying to change settings (like, mic settings or notifications settings) from the app, I have to go to iPhone settings:
if let settingsUrl = URL(string: UIApplication.openSettingsURLString) {
UIApplication.shared.open(settingsUrl)
}
But when I'm back I'm shown the OnboardViewController again as if appDelegate doesn't remember that current root controller is mcVC (or, rather, UINavigationController with embed mcVC).
So, why is that, and what is the right way to fix this?
I would like to launch my app from a local notification that will appear when the home screen is locked or when the user is in another app based on similar discussions here and here I have the following code in my AppDelegate:
func userNotificationCenter(_: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
switch response.actionIdentifier {
case "play":
var setAlarmVC = self.window?.rootViewController as? SettingAlarmViewController
if setAlarmVC == nil {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
setAlarmVC = storyboard.instantiateViewController(withIdentifier: "AlarmViewController") as? SettingAlarmViewController
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = setAlarmVC
self.window?.makeKeyAndVisible()
}
case "snooze":
print("I pressed pause")
default:
break
}
completionHandler()
}
Within my SettingAlarmViewController's viewDidLoad, I have set up some simple print-outs
override func viewDidLoad() {
super.viewDidLoad()
print("Setting Alarm View Controller was instantiated")
}
When I press play from the local notification while the app is in the background, I get the console print-out as expected:
Setting Alarm View Controller was instantiated
But the app does not actually launch and Setting Alarm View Controller does not appear. If I then click on the app, a fresh Setting Alarm View Controller is the first visible thing. I feel like I must be missing something obvious, but I cannot figure out what it is.
EDIT: Doing more testing. When the notification appears on the lock screen and the user presses "play" from the lock screen, the password / unlock screen does not appear, but the app still launches and I get the print-out " Setting Alarm View Controller was instantiated"
Well, a day of my life wasted on this, here is the problem so that others do not have the same issue: developer.apple.com/documentation/usernotifications/… you must ad [.foreground] to your Notification Action, as in let playAction = UNNotificationAction(identifier: "play", title: "play", options: [.foreground])
I already get the data from one signal (additional Data). But I want to present view controller by clicking the push notification itself. Can someone help me. Thanks in advance.
Did you check OneSignal's docs on Deep Linking? https://documentation.onesignal.com/docs/links
There is a demo project on Github that might help you: https://github.com/OneSignal/OneSignal-iOS-SDK/tree/master/Examples
add this in your didFinishLaunchingWithOptions
this code will check that if app was launched using appIcon or tapping on notification
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let tabBar = storyBoard.instantiateViewController(withIdentifier: "MainNavigationController")
as? UINavigationController
self.window?.rootViewController = tabBar
self.window?.makeKeyAndVisible()
if let notification = launchOptions?[.remoteNotification] as? [String: AnyObject] {
// 2
let aps = notification["aps"] as! [String: AnyObject]
let vc = storyBoard.instantiateViewController(withIdentifier: "EmergencyRequestViewController") as? EmergencyRequestViewController
tabBar?.pushViewController(vc!, animated: true)
}
}
My app has 5 tab bar and each time i receive push notification i would like the app to navigate to 3rd tab in the index. I able to achieve it when the app is in foreground or background (in active state). if the app is closed and i try to open the push notification the app opens and crashes.
Below is the code which i have
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject])
{
let tabbar:UITabBarController = self.window?.rootViewController as! UITabBarController
tabbar.selectedIndex = 3
}
Kindly let me know what i am doing wrong.
Try adding the below code in the end of diFinishLaunchingWithOptions method:
if let notification = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] as? [String : AnyObject] {
_ = notification["aps"] as! [String : AnyObject]
(window?.rootViewController as! UITabBarController).selectedIndex = 3
}
Are you debugging your code? If the app crashes there, it can very possibly be that the window.rootViewController is not a UITabBarController.
You can either debug that or change the as! in as?
And:
tabbar?.selectedIndex = 3
If the app doesn't crash, your tab bar controller is somewhere else. Just find it.
Also remember to check for your notification in the options dictionary.
I'm working on an app in Swift using push notifications. So far I have the following code in my AppDelegate:
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
println("Received alert and opened it")
debugPrintln(userInfo)
if application.applicationState == UIApplicationState.Active {
// App in foreground
println("App in foreground already")
} else {
// App in background
if let tripId = (userInfo["trip"] as? String)?.toInt() {
println(tripId)
Trips.load(tripId) { (responseCode, trip) in
debugPrintln("Got the trip")
if let trip = trip {
if let window = self.window {
if let rootViewController = window.rootViewController {
if let storyboard = rootViewController.storyboard {
let viewController = storyboard.instantiateViewControllerWithIdentifier("Trip") as! TripViewController
viewController.trip = trip
rootViewController.presentViewController(viewController, animated: true, completion: nil)
} else {
println("No storyboard")
}
} else {
println("No root view controller")
}
} else {
println("No window")
}
}
}
} else {
println("Failed to get trip id")
}
}
}
The storyboard is constructed that when the app first opens, it opens to the LoginViewController, which checks login state and redirects to a NavigationController containing a list of trips. From the list, a user can tap a trip to open the TripViewController (see screenshot).
When I run my app and test tapping on a push notification, the app loads the trip list and I see the following log in my console:
2015-09-04 09:50:07.158 GoDriver[883:377922] Warning: Attempt to present <GoDriver.TripViewController: 0x15f5b260> on <GoDriver.LoginViewController: 0x15d910e0> whose view is not in the window hierarchy!
Do I have to load up my Navigation Controller and populate it with the TripViewController?
If you are using UIStoryBoard and using the initialViewController, iOS automatically does the needful i.e loads it up, creates navigationController if needed and loads it to window.
However in this case you will need to do this bit manually. You would need to create a UINavigationController, populate it with your TripViewController and hook it with UIWindow.