I write some app that sends local notification with delay and when the notification received i want to decide what to do based on device movement.
if device is in move - set the same notification with new delay and stay in background.
if device not in move - pop specific view controller.
i do succeed with the "no drive" mode but when the device is in move - i don't really know hot to handle this situation.
here is my code for now, hope for some help
thanks!
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
NSLog(#"Notification recieved from background...");
//check if device is in move
CLLocationManager *locationManager = [[CLLocationManager alloc]init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
locationManager.distanceFilter = 50;
[locationManager startMonitoringSignificantLocationChanges];
if (locationManager.location.speed > 10) {
NSLog(#"Device is in drive....");
notification.fireDate = [NSDate dateWithTimeIntervalSinceNow:10];//TODO - Debug Set Real Time Before publish
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
NSLog(#"New Notification sent to device");
self.window.rootViewController = nil;
[self.window makeKeyAndVisible];
}
else{
NSLog(#"Device is not in drive....");
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
IGUViewFillDetailsController *vc = (IGUViewFillDetailsController *)[mainStoryboard instantiateViewControllerWithIdentifier:#"IGUViewFillDetailsController"];
vc.dic = notification.userInfo;
UINavigationController *navVC = [[UINavigationController alloc] initWithRootViewController: vc];
self.window.rootViewController = vc;
//[self.window addSubview:vc.view];
[self.window makeKeyAndVisible];
}
}
Problem1:
You scheduled a notification and it will show up at the fire date, you can cancel the notification 1 second before the fire date and schedule it again. Say you have this notification to be fired in 10 seconds, you use a NSTimer that will be fired in 9 second, in the selector of the timer you check if the user is moving or not, if he is moving, you cancel the notification and delay it by 10 seconds and schedule it again, remember you also have to update the timer to do the check before next fire date of new notification.
Problem2:
It is the default behaviour, iOS will take a snap shot before app enter background, and when app resign background, it will show this snap shot, you can add a empty view in applicationDidEnterBackground, then this empty view will show up before the wanted view.
Related
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've a chat view,i'm chating with someone and when i enter in background,and once again enter in foreground all message have been removed(refresh),how can i got same chat message.
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
[[UIApplication sharedApplication] cancelAllLocalNotifications];
application.applicationIconBadgeNumber = 0;
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
SPHViewController *chatView = [[SPHViewController alloc] initWithNibName:#"SPHViewController" bundle:nil];
chatView.strCallerName = [NSString stringWithFormat:#"%#",strSelectedCallerName];
self.window.rootViewController = chatView;
[self.window makeKeyAndVisible];
}
You are basically resetting the app state every time the app enters foreground. That's not the place to instantiate your view controller and set the app's main window. You need to do that in your applicationDidFinishLaunching:
Hey I'm new to iPhone and I have been trying to use an Apple push notification. Basically, what I want to do is that when user clicks on the received push notification message, then i need to open a specific view controller. I have added custom data with key parameter "type" to my payload JSON, so on behalf of notification type value i need to open particular view controller instead of the main view controller.
here is my payload JSON :
{"aps":{"alert":"This is testing message","type":"Notify","badge":1,"sound":"default"}}
my code is :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
splashViewController = [[SplashViewController alloc] initWithNibName:#"SplashViewController" bundle:nil];
self.window.rootViewController = splashViewController;
[self.window makeKeyAndVisible];
return YES;
}
- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo
{
//this will call when your app will get any notification from server.
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
[[UIApplication sharedApplication] cancelAllLocalNotifications];
NSDictionary *aps = (NSDictionary *)[userInfo objectForKey:#"aps"];
NSMutableString *notificationType = [aps objectForKey:#"type"];
NSLog(#"notification type is = %#", notificationType);
//For redirect to the view
UIViewController *viewController;
if([notificationType isEqualToString:#"Notify"]){
//Notify updates
UpdatesViewController *uvc1 = [[UpdatesViewController alloc] initWithNibName:#"UpdatesViewController" bundle:nil];
viewController = uvc1;
}
else {
//Voting & QA
VotingViewController *votingViewController = [[VotingViewController alloc] initWithNibName:#"VotingViewController" bundle:nil];
viewController = votingViewController;
}
[self.window.rootViewController presentViewController:viewController animated:YES completion:NULL];
}
My code is not presenting other view controller. As mentioned in my code, i am getting two kind of web service (notification type) 1. Notify and 2. Voting from Apple. i dont know how to present specific view controller on behalf of notification type, if type is "notify" then i need open UpdatesViewController else it will open other viewcontroller. If anyone knows how to do this, please help me.
Thanks.
//For redirect to the view
UIViewController *uvc;
if([notificationType isEqualToString:#"Notify"]){
UIViewController *updates = [[UpdatesViewController alloc] initWithNibName:#"UpdatesViewController" bundle:nil];
// add updates specific data updates.data = [aps objectForKey:#"data"];
uvc = updates;
}
else if([notificationType isEqualToString:#"Voting "]) {
UIViewController *voting = [[VotingViewController alloc] initWithNibName:#"VotingViewController" bundle:nil];
// add voting specific data voting.data = [aps objectForKey:#"data"];
uvc = voting;
}
[self.window.rootViewController presentViewController:uvc animated:YES completion:NULL];
you should check the aps in didFinishLaunchingWithOptions.
didReceiveRemoteNotification only works when app is running or suspended.
Hey I'm new to iPhone and I have been trying to use an Apple push notification. Basically, what I want to do is that when user clicks on the received push notification message, then i need to open a specific view controller, it is working for me. I have added custom data with key parameter "type" to my payload JSON.
here is my payload JSON :
{"aps":{"alert":"This is testing message","type":"Notify","badge":1,"sound":"default"}}
here is my code :
#synthesize viewControllerNotify;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
[[UIApplication sharedApplication] cancelAllLocalNotifications];
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
screenBounds = [[UIScreen mainScreen] bounds];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
if (launchOptions != nil) {
//Launched from push notification
NSDictionary *userInfo = [launchOptions valueForKey:#"UIApplicationLaunchOptionsRemoteNotificationKey"];
NSDictionary *apsInfo = [userInfo objectForKey:#"aps"];
NSMutableString *notificationType = [apsInfo objectForKey:#"type"];
//For redirect to the view
if([notificationType isEqualToString:#"Notify"]){
//Notify updates
UpdatesViewController *uvc1 = [[UpdatesViewController alloc] initWithNibName:#"UpdatesViewController" bundle:nil];
self.viewControllerNotify = uvc1;
}
else if([notificationType isEqualToString:#"Voting"] || [notificationType isEqualToString:#"QA"]){
//Voting & QA
VotingQAViewController *votingQAViewController = [[VotingQAViewController alloc] initWithNibName:#"VotingQAViewController" bundle:nil];
self.viewControllerNotify = votingQAViewController;
}
else if([notificationType isEqualToString:#"Survey"] || [notificationType isEqualToString:#"Quiz"]){
//Survey & Quizzes
SurveysViewController *surveysViewController = [[SurveysViewController alloc] initWithNibName:#"SurveysViewController" bundle:nil];
self.viewControllerNotify = surveysViewController;
}
UINavigationController *nav=[[UINavigationController alloc]initWithRootViewController:self.viewControllerNotify];
self.window.rootViewController = nav;
[nav setNavigationBarHidden:YES];
}
else{
//Normal Launch
if(screenBounds.size.height == 568) {//iPhone5
splashViewController = [[SplashViewController alloc] initWithNibName:#"SplashViewController_5" bundle:nil];
}
else{
splashViewController = [[SplashViewController alloc] initWithNibName:#"SplashViewController" bundle:nil];
}
UINavigationController *nav=[[UINavigationController alloc]initWithRootViewController:splashViewController];
self.window.rootViewController = nav;
[nav setNavigationBarHidden:YES];
}
[self.window makeKeyAndVisible];
return YES;
}
- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo
{
NSDictionary *aps = (NSDictionary *)[userInfo objectForKey:#"aps"];
int badge = [[aps objectForKey:#"badge"] intValue];
NSMutableString *notificationType = [aps objectForKey:#"type"];
NSLog(#"Number of badge is = %d", badge);
NSLog(#"notification type is = %#", notificationType);
//For redirect to the view
if([notificationType isEqualToString:#"Notify"]){
//Notify updates
UpdatesViewController *uvc1 = [[UpdatesViewController alloc] initWithNibName:#"UpdatesViewController" bundle:nil];
self.viewControllerNotify = uvc1;
}
else if([notificationType isEqualToString:#"Voting"] || [notificationType isEqualToString:#"QA"]){
//Voting & QA
VotingQAViewController *votingQAViewController = [[VotingQAViewController alloc] initWithNibName:#"VotingQAViewController" bundle:nil];
self.viewControllerNotify = votingQAViewController;
}
else if([notificationType isEqualToString:#"Survey"] || [notificationType isEqualToString:#"Quiz"]){
//Survey & Quizzes
SurveysViewController *surveysViewController = [[SurveysViewController alloc] initWithNibName:#"SurveysViewController" bundle:nil];
self.viewControllerNotify = surveysViewController;
}
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
[[UIApplication sharedApplication] cancelAllLocalNotifications];
UINavigationController *nav=[[UINavigationController alloc]initWithRootViewController:self.viewControllerNotify];
self.window.rootViewController = nav;
[nav setNavigationBarHidden:YES];
[self.window makeKeyAndVisible];
}
My question is: Is this the correct way to redirect to the view controller when push notification is received?
Using the above code, it is redirecting to the view controller class on behalf on Notification type (custom key of notification payload json) successfully in forground and background mode but that redirected View Controller back button is not working. I don't know where i am doing wrong here. If anyone knows then please help me. Thanks.
Better You can post the notification using NSNotificationCentre in didReceiveRemoteNotification and receive the notification on the other classes. So that you can push the required view controller from the current view controller (need not to set as root view controller). Then the back button will works.
For Ex.
[[NSNotificationCenter defaultCenter] postNotificationName:kMesssagePushNotification object:nil userInfo:userInfo];
The back button is not working, because you are setting the target view as a root view. You should instead construct the full navigation stack, i.e. usually, if you have a navigation view controller as a root view controller, you should create that first and then construct all the view controllers that are between the root and your leaf view.
For example, if MainViewController would be your normal start view and the back button from UpdatesViewController should lead to MainViewController you would do:
MainViewController *mainVC = [[MainViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
UpdatesViewController *updatesVC = [[UpdatesViewController alloc] initWithNibName:#"UpdatesViewController" bundle:nil];
UINavigationController *navVC=[[UINavigationController alloc]initWithRootViewController:mainVC];
[navVC setViewControllers:#[mainVC, updatesVC] animated:NO];
self.window.rootViewController = navVC;
There are two chances that you will access the notification data.
If you receive the notification when your app isn't on, then click the notification and you will get the notification data in the following function:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
use
launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]
to access the notification data and open the view controller you expected.
If you receive the notification when your app is on, but your app can be in background or foreground. If it is the former case, you will receive the notification in notification center, your app will invoke the following function after you click the notification:
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
If it is the later case, you app will directly invoke the function before. And you can distinguish them using the flowing code:
UIApplicationState state = [[UIApplication sharedApplication] applicationState];
if (state == UIApplicationStateBackground || state == UIApplicationStateInactive){
//notification is received when your app is in background
//open the view controller you expected
}else if(state == UIApplicationStateActive){
//notification is received when your app is in foreground
//do nothing
}
sorry for my pool English, hope it helps~
I am working on an application that uses iOS's UILocalNotifications to alert the user that action needs to be completed on their part. I am able to create my notifications and have them fire properly. However, when returning to the app I am having an issue. After the first time a notification fired my 'application: didRecieveLocalNotification' runs every time, with the 1st notifications data. I can log out all the notifications in the queue, and even if the queue is empty it will still run the notification block. Has anyone else ran into this problem or know how to fix it. I have included my didRecieveLocalNotification code below.
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
if (notification) {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
[(UITabBarController *)self.window.rootViewController setSelectedIndex:1];
UINavigationController *nav = [[(UITabBarController *)self.window.rootViewController viewControllers] objectAtIndex:1];
IMTUpdateRewardViewController *rvc = [storyboard instantiateViewControllerWithIdentifier:#"updateReward"];
[rvc loadPushNotification:notification];
[nav pushViewController:rvc animated:NO];
}
}
I have ran into a similar problem. Eventually the culprit was a bug on my part, which was related to generating reminders to events. And if upon return from background, there were events which have already began, then a local notification was generated, and fired immediately. In short, when you encounter something like this, put a small debug printout at your UILocalNotification generating methods