i have 2 local notifications in my app. i want to present view1 from notification1 and view2 from notification2 . how can i do it ? and i also want to show it on any view that was before going to inactive or background state by pressing home button.
UILocalNotification *notif1=[UILocalNotification alloc]init];
UILocalNotification *notif2=[UILocalNotification alloc]init];
//when user tapped on notif1
[self presentViewController:vc1 animated:YES completion:nil];
//when user tapped on notify2
[self presentViewController:vc2 animated:YES completion:nil];
You can use the -application:didReceiveLocalNotification:notification delegate method.
In your app delegate, implement this delegate as shown below and check if the app is currently active. If it isn't, tell the root view controller to present your new view controllers.
Here's an example:
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
if (application.applicationState != UIApplicationStateActive) {
ViewControllerName *viewController = [ViewControllerName new];
[self.window.rootViewController presentViewController:viewController];
}
}
You will have to modify this a bit to handle the different notifications; however, that shouldn't be too difficult.
Related
In the default - (void)applicationDidBecomeActive:(UIApplication *)application { method in appDelegate, Apple includes the comment:
//This may also be a good place to direct someone
to a certain screen if the app was in background but they just clicked on a notification
I am trying to do this for local notifications, but can't figure out how to direct the user to a certain screen. The docs say that you can check for an URL but even so, I don't know how to specify an NSUrl for a screen within an app.
This seems like a common use case, we click on notifications all the time that take us to specific parts of app, but not finding any good resources.
Thanks in advance for any suggestions.
You have to use didReceiveLocalNotification or didReceiveNotificationResponse delegate method in your AppDelegate.m file based on which Notification you have implemented
For UILocalNotification:
-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
// Your redirection code goes here like shown below
MyViewController *controller = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"ViewController"];
[self.window.rootViewController.navigationController pushViewController:controller animated:YES];
}
For UNNotification
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void (^)(void))completionHandler {
// Your redirection code goes here like shown below
MyViewController *controller = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"ViewController"];
[self.window.rootViewController.navigationController pushViewController:controller animated:YES];
}
For more reference on UNNotification or handling Local Notification, please refer https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/SchedulingandHandlingLocalNotifications.html
I have tabbar controller having three tab, attached three navigation controller I want to go to second controller of navigation controller just like whatsapp. I handled successfully for background state, but for not running state. Below is my code in didfinishlaunch delegate method of uiapplication.
if (launchOptions != nil) {
// Launched from push notification
NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
[self performSelector:#selector(notificationObserverAfterDelay:) withObject:notification afterDelay:2.0];
}
-(void)notificationObserverAfterDelay:(NSDictionary *)userInfo
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"RefreshUIChatNotRunningState" object:self userInfo:userInfo];
}
Nazish Ali,
Sending out notification after delay of 2 seconds is really not a good idea.
Declare a method which accepts your userInfo dictionary as argument in your viewController having tab bar.
lets call it as,
YourViewController.h
-(void)appStartedFromPushNotification : (NSDictionary *)userInfo;
YourViewController.m
-(void)appStartedFromPushNotification : (NSDictionary *)userInfo {
//now the control has reached yourViewController with tab bar
//change the tab bar selection and perform segue and load the next viewController and use prepareforSgue to pass the data
}
Now why YourViewController only why not the actualViewController which anyway needs to be loaded ??? Reason you dont want mess with navigation stack manually. Because YourViewController is the child of UINavigationController and UINavigationController is your rootView controller YourViewController will be loaded automatically. So just access it and ask it to perform the tab change and load viewControllers so your navigation stack will continue to be stable :)
finally in Appdelegate,
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSDictionary *userInfo = [launchOptions valueForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (launchOptions) {
[self handleReceiveRemoteNotification: userInfo];
}
return YES;
}
Declare a method in AppDelegate.m and access the YourViewController instance and handover data to it thats all :)
- (void) handleReceiveRemoteNotification:(NSDictionary *)userInfo{
UINavigationController *rootViewController = (UINavigationController *)self.window.rootViewController;
for(UIViewController *viewController in rootViewController.viewControllers){
if([viewController isKindOfClass:[YourViewController class]]) {
[viewController appStartedFromPushNotification:userInfo];
}
}
That should do the job :) Happy coding :)
I'm using modal segue (without navigation controller) to move between viewController A and viewController B like so:
viewA *first = [self.storyboard instantiateViewControllerWithIdentifier:#"viewA"];
[self presentViewController:first animated:YES completion:nil];
And to move back :
[self dismissViewControllerAnimated:YES completion:nil];
Now, I want to know from the AppDelegate whether A or B is the current view right now.
The problem is when I'm checking
[(AppDelegate *)[[UIApplication sharedApplication] delegate] window]
the answer is always view A - the first one.
I've tried to set the current view every time I'm using modal segue like so:
viewA *first = [self.storyboard instantiateViewControllerWithIdentifier:#"viewA"];
[self presentViewController:first animated:YES completion:^
{
[[(AppDelegate *)[[UIApplication sharedApplication] delegate] window] setRootViewController:first];
}];
But it cause a few bugs (like unable to use "dismissViewControllerAnimated"),and it's impossible to work like that in every segue in a big project with many segues.
How should I work with that? And how should I detect the current view in more appropriate way?
As was answered here
UIWindow *topWindow = [[[UIApplication sharedApplication].windows sortedArrayUsingComparator:^NSComparisonResult(UIWindow *win1, UIWindow *win2) {
return win1.windowLevel - win2.windowLevel;
}] lastObject];
UIView *topView = [[topWindow subviews] lastObject];
However, doing this logic here sounds like bad architecture. What is the reason for you needing to know which view is currently presented inside of your AppDelegate?
Edit It seems like you want to respond to the applicationWillResignActive event from your view controller. Use something like this in the your game view controller.
- (void) applicationWillResign {
NSLog(#"About to lose focus");
}
-(void) viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(applicationWillResign)
name:UIApplicationWillResignActiveNotification
object:NULL];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[[NSNotificationCenter defaultCenter]
removeObserver:self];
}
The appDelegate's window won't be equal to either view controller (viewControllerA or viewControllerB). You can ask the window for it's root view controller...
AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
if (appDelegate.window.rootViewController == viewControllerA) {
// always true if you always start the app with viewControllerA
... and you can ask any view controller for the view controller it presented...
if (appDelegate.window.rootViewController.presentedViewController == viewControllerB) {
// will be true if viewControllerA has presented viewControllerB
But this is a tricky game. If, for example, viewControllerB presents some other viewControllerC, the condition above will continue to be true.
See the #Eric answer here (not the accepted answer) for a way to find the topmost vc in general.
I need to present a view when the user enters the app after having received a Local Notification.
I wrote the below code in the didReceiveLocalNotifications Method.
NotificationModelClass *remainderAlert = [[NotificationModelClass alloc]initWithNibName:#"NotificationModelClass" bundle:nil];
[remainderAlert showRemainderAlert1];
[self.viewController presentModalViewController:remainderAlert animated:YES];
It is working fine when the user enter the background through MainView Controller. But I want to present that view in any viewController.
Try something like this for presenting any where in the app:
#define AppDelegateObject ((AppDelegate *)[[UIApplication sharedApplication] delegate])
[AppDelegateObject.window.rootViewController presentModalViewController: remainderAlert animated:YES];
If your appdelegate is the receiver of the notification then do it like this:
[self.window.rootViewController presentModalViewController: remainderAlert animated:YES];
Why do I want to use presentModalViewController in AppDelegate?
- Processing didReceiveLocalNotification, so I can launch a seperate modalView on top of my app to process the notification
What does my view architecture look like?
- Using storyboards
- MainStoryBoard: ->TabBarController->NavigationController
What's happening?
- Nothing, that's the problem :-D
- When I press the action button from the UILocalNotification, the app opens, but just shows the last open view from the tabbarcontroller.
As you can see below my last effort was to present the modalViewController on top of that current view, like so:
[self.window.rootViewController.tabBarController.selectedViewController.navigationController presentModalViewController:navigationController animated:YES];
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
UIApplicationState state = [application applicationState];
if (state == UIApplicationStateInactive) {
// Application was in the background when notification was delivered.
NSLog(#"Received notification while in the background");
}
else {
NSLog(#"Received notification while running.");
}
MedicationReminderViewController *controller = [[UIStoryboard storyboardWithName:#"ModalStoryBoard" bundle:nil] instantiateViewControllerWithIdentifier:#"MedicationReminderVC"];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:controller];
[self.window.rootViewController.tabBarController.selectedViewController.navigationController presentModalViewController:navigationController animated:YES];
}
Update
Seems that this is nil:
self.window.rootViewController.tabBarController.selectedViewController.navigationController
Solution
[self.window.rootViewController presentModalViewController:navigationController animated:YES];
Try this :
[self.window.rootViewController presentModalViewController:controller
animated:YES];
Have you tried the following?
[self.window.rootViewController.tabBarController.selectedViewController presentModalViewController:navigationController animated:YES];
That said, even if this works, I would really urge you to reconsider your design choices to avoid having to do this. Traversing the navigation stack in this way to access stuff can get very messy and I'd strongly advise against it.