When user clicks the notification, I want the app to open up to the third tab on my tab bar controller. I can get the notification to fire, but not the opening up right part. In my app's didFinishLaunchingWithOptions I have:
UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (localNotif) {
tabBarController.selectedIndex = 3;
}
And then in AppDelegate as well, I have:
- (void)application:(UIApplication *)application
didReceiveLocalNotification:(UILocalNotification *)notification {
application.applicationIconBadgeNumber = 0;
NSString *reminderText = [notification.userInfo
objectForKey:kRemindMeNotificationDataKey];
[viewController showReminder:reminderText];
tabBarController.selectedIndex = 3;
}
However, clicking the notification just opens it up, like normal, to the first tab.
Here's an example. And also the third tab would be tabBarController.selectedIndex = 2 since the count starts from 0.
Related
I'm using the below code to set a badge on my app icon when a notification is received while the app is running in the background. That said, my code/log is never triggered when a notification is received while the app is minimized (see log: "NSLog APP WAS IN BACKGROUND") and I'm not sure why?
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
[[NSNotificationCenter defaultCenter] postNotificationName:#"pushNotification" object:nil userInfo:userInfo];
NSLog(#"application Active - notication has arrived while app was opened");
completionHandler(UIBackgroundFetchResultNewData);
NSLog(#"Notification received when open");
if(application.applicationState == UIApplicationStateInactive) {
NSLog(#"Inactive - the user has tapped in the notification when app was closed or in background");
completionHandler(UIBackgroundFetchResultNewData);
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UITabBarController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"tabBarController"]; // determine the initial view controller here and instantiate it with [storyboard instantiateViewControllerWithIdentifier:<storyboard id>];
[viewController setSelectedIndex:0];
;
self.window.rootViewController = viewController;
[self.window makeKeyAndVisible];
[[NSNotificationCenter defaultCenter] postNotificationName:#"myNotificationReceived" object:nil];
}
if (application.applicationState == UIApplicationStateBackground) {
NSLog(#"APP WAS IN BACKGROUND");
static int i=1;
[UIApplication sharedApplication].applicationIconBadgeNumber = i++;
}
}
- (void)applicationDidEnterBackground:(UIApplication *)application{
static int i=0;
[UIApplication sharedApplication].applicationIconBadgeNumber = i;
NSLog(#"Triggered!");
}
This is the correct behaviour for a remote notification.
Your app won't receive the didReceiveRemoteNotification call when your app is in the background, unless the user taps the notification alert.
Here's how it works.
1) When your app is in the background (or suspended) and a remote notification is received, an iOS system alert is shown.
2) If the user opens your app by tapping the notification alert, then your app will move the foreground and didReceiveRemoteNotification will be called.
3) If the user ignores the notification, or dismisses it, then your app remains in the background, and didReceiveRemoteNotification will not be called.
That said, there is no need to set the application badge in code. Your push notification payload, can include a key which iOS uses to set the application badge when the system receives your notification.
You simple include the key badge in your notification's payload:
{
"aps" : {
"alert" : {
"title" : "Notification title",
"body" : "Notification body"
},
"badge" : 5
}
}
I'd suggest you take a look at Apple's documentation for creating a remote notification payload, which explains all the options:
https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification?language=objc
That all being said, it is possible to make sure iOS calls didReceiveRemoteNotification when your app is in the background.
To achieve this, you need to set the content-available parameter in your payload and send a "silent" notification. A silent notification means that the user will never see an alert, but your app will be silently brought to the foreground for a finite amount of time, and didReceiveRemoteNotification will be called.
It's not an appropriate choice for your scenario, though. It's intended for updating an app's content, not just updating the badge.
However, if you're interested in silent notifications, you can see the documentation here:
https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_updates_to_your_app_silently?language=objc
[UIApplication sharedApplication].applicationIconBadgeNumber = 3;
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 trying to open child view(PostReaderViewController, the fourth view on Image ) when application is lunched through Push notification It's. Storyboard Image :
This is my Code :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
...
//Detecting if the app was lunched by clicking on push notification :
NSDictionary *userInfo = [launchOptions valueForKey:#"UIApplicationLaunchOptionsRemoteNotificationKey"];
NSDictionary *apsInfo = [userInfo objectForKey:#"aps"];
if(apsInfo) {
UIStoryboard *mainstoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
PostReaderViewController* postReader = (PostReaderViewController *)[mainstoryboard instantiateViewControllerWithIdentifier:#"postReaderView"];
CostumSDPost *tempPost = [[CostumSDPost alloc] init];
tempPost.ID = userInfo[#"post_id"];
postReader.thePost = tempPost;
[self.window.rootViewController presentViewController:postReader animated:YES completion:NULL];
//userInfo[#"post_id"]);
}
return YES;
}
When I launch my APP via push notification no error are shown but unfortunly it start and show the default View (third View on image).
Note that I'm using SWRevealMenu and the Intial Point (first View on image) is the Reveal View Controller
self.window.rootViewController needs to perform the presentation in either viewDidLoad or in viewDidAppear. If you do it earlier then either rootViewController will be nil or the view controller hierarchy won't be in a state that can accommodate a presentation.
To slove This issue :
First I've created Global BOOL variable then in the AppDelegate I set this var to YES if app is lunched via push notif like this :
//Detecting if the app was lunched by clicking on push notification :
NSDictionary *userInfo = [launchOptions valueForKey:#"UIApplicationLaunchOptionsRemoteNotificationKey"];
NSDictionary *apsInfo = [userInfo objectForKey:#"aps"];
if(apsInfo) {
// Set my global Var to YES
GlobalSingleton *global = [GlobalSingleton sharedInstance];
global.displayFirstPost = YES; }
Then In my Home screen I check if this variable == YES then navigate to next screen auto else show the Home screen :
GlobalSingleton *global = [GlobalSingleton sharedInstance];
if (global.displayFirstPost) {
// NAvigation code to the third Screen
}
I am using local notifications on my app. I handle a notification perfectly when it arrives and you press on it even the app is running even not, and when you open the notification from the "Notifications" of the device. BUT when the app is not running and you open direct the app then the notification screen doesn't open and the badge number is not going to 0. What am I missing?
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UILocalNotification *locationNotification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (locationNotification) {
UILocalNotification *localNotif =
[launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
NotificationsViewController *vc = nil;
if (localNotif) {
//base on notification create right view controller
vc = [[NotificationsViewController alloc] init];
NSLog(#"Recieved Notification %#",localNotif);
}
else
{
//create default view controller
vc = [[NotificationsViewController alloc] init];
}
// Add the view controller's view to the window and display.
_window.rootViewController = vc;
[_window makeKeyAndVisible];
// Set icon badge number to zero
application.applicationIconBadgeNumber = 0;
}
return YES;
}
-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
NotificationsViewController *vc = nil;
vc = [[NotificationsViewController alloc] init];
_window.rootViewController = vc;
// Set icon badge number to zero
application.applicationIconBadgeNumber = 0;
//We take the rootViewController first which is expected to be a UINavigationController in your case
}
if you don't open the app from a notification, the app doesn't know there are notifications
Checking applicationIconBadgeNumber you can know if there is a notification, but you can't get the notification info (message or other data you send)
When your app is not running
if you "didFinishLaunchingWithOptions" will be called not didReceiveLocalNotification, you should track the parameter launchOptions to detect start mode:
If the app start direct from app icon you should not redirect user to notification screen.
If the app start from NSNotification you should redirect user to notification, unschedule notification, update app icon badges etc...
So in this case when you open the app from app icon locationNotification may nil.
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.