I have a textview and an imageview in my app so i can display the notification text and the image that i want to show. i receive this image from a url that i send via the notification. When i send notifications to my application and the app isn't running, the textview and the imageview doesnt show the content, but when the app is running or when the app state is in background the content updates.
I suppose that i have to configure the didFinishLaunchingWithOptions function when the app starts in order to update the fields of the view controller.
how can i do that? and why the didReceiveRemoteNotification function doesnt update the view when the app starts and updates the view only in two states (active & background)?
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
NSLog(#"New notification received!");
[self.window makeKeyAndVisible];
//Notification recieved & handle the aps
NSDictionary * notificationDict = [userInfo objectForKey:#"aps"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"refreshView" object:notificationDict];
NSString * alertString = [notificationDict objectForKey:#"alert"];
NSString * serverUrl = [notificationDict objectForKey:#"acme"];
NSLog(#"Notification text is: %#", alertString);
[[NSUserDefaults standardUserDefaults] setObject: alertString forKey: #"alertMSG"];
[[NSUserDefaults standardUserDefaults] synchronize];
//handle the notification when the app is active, inactive or in background
if ( application.applicationState == UIApplicationStateActive )
{
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [sb instantiateViewControllerWithIdentifier:#"viewController2"];
[self.window.rootViewController presentViewController:vc animated:YES completion:nil];
application.applicationIconBadgeNumber = 0;
}
else if(application.applicationState == UIApplicationStateInactive)
{
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [sb instantiateViewControllerWithIdentifier:#"viewController2"];
[self.window.rootViewController presentViewController:vc animated:YES completion:nil];
application.applicationIconBadgeNumber = 0;
}
else //ApplicationState Background
{
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [sb instantiateViewControllerWithIdentifier:#"viewController2"];
[self.window.rootViewController presentViewController:vc animated:YES completion:nil];
application.applicationIconBadgeNumber = 0;
}
}
EDIT:
I have configure the didFinishLaunchingWithOptions to starts my controller when the app is launched from a notification, but the content still doesn't update beside the fact that i have signed an observer between the view controller and the app delegate. what am i missing ?
here is the code :
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions{
if (launchOptions != nil)
{
NSDictionary * dictionary = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (dictionary != nil)
{
[self handleRemoteNotification:dictionary];
}
}
}
-(void)handleRemoteNotification:(NSDictionary*)payload{
NSDictionary * notificationDict = [payload objectForKey:#"aps"]; //extract some information from payload
[[NSNotificationCenter defaultCenter] postNotificationName:#"refreshView" object:notificationDict];
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [sb instantiateViewControllerWithIdentifier:#"viewController2"];
[self.window.rootViewController presentViewController:vc animated:YES completion:nil];
[UIApplication sharedApplication].applicationIconBadgeNumber = 0;}
ViewController2.m:
- (void)viewDidLoad{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
//Observer for remote notifications
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(refreshView:) name:#"refreshView" object: nil];
notifTextf.delegate = self;
}
//Update View when notification is received
-(void)refreshView:(NSNotification *) notification
{
// Do whatever you like to respond to text changes here.
NSLog(#"observer notification message text is: %#", [notification.object objectForKey:#"alert"]);
NSLog(#"observer notification message url is: %#", [notification.object objectForKey:#"acme"]);
[self.notifTextf setText: [notification.object objectForKey:#"alert"]];
//Download image from Url sended by notification and display it
NSString * imageurl = [notification.object objectForKey:#"acme"];
NSURL *url = [NSURL URLWithString:imageurl];
self.notifImg.image = [UIImage imageWithCIImage:[CIImage imageWithContentsOfURL:url]];
}
why the didReceiveRemoteNotification function doesnt update the view
when the app starts and updates the view only in two states (active &
background)?
If the app is not running when a push notification arrives, the system launches the app and provides the appropriate information in the launch options dictionary. The app does not call application:didReceiveRemoteNotification: method to handle that push notification. Instead, your implementation of the application:willFinishLaunchingWithOptions: or application:didFinishLaunchingWithOptions: method needs to get the push notification payload data and respond appropriately.
Implement the application:didReceiveRemoteNotification:fetchCompletionHandler: method instead whenever possible (iOS 7 and above).
Unlike the application:didReceiveRemoteNotification: method, which is called only when your app is running in the foreground, the system calls the application:didReceiveRemoteNotification:fetchCompletionHandler: method when your app is running in the foreground or background. In addition, if you enabled the remote notifications background mode (to support this mode, include the UIBackgroundModes key with the remote-notification value in your app’s Info.plist file), the system launches your app (or wakes it from the suspended state) and puts it in the background state when a push notification arrives. However, the system does not automatically launch your app if the user has force-quit it. In that situation, the user must relaunch your app or restart the device before the system attempts to launch your app automatically again.
Continue reading...
Related
I'm sending push notification to app which is terminated and it seems that only this method is triggered. I want to open ViewController when app is launched with push notification, but it doesn't do anything just opens app.
I tried to achieve that with this code:
if (launchOptions != nil) {
NSDictionary* userInfo = [launchOptions valueForKey:#"UIApplicationLaunchOptionsRemoteNotificationKey"];
NSDictionary *apsInfo = [userInfo objectForKey:#"aps"];
if (apsInfo)
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"openNews" object:nil userInfo:userInfo];
}
}
and tried this as well ..
if (launchOptions != nil) {
NSDictionary* userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (userInfo != nil)
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"openNews" object:nil userInfo:userInfo];
}
}
Any ideas how to launch ViewController when app is terminated with push notification?
So I have tried to save notification info to NSUserDefaults if launchOptions != nil just to check if Im receiving notification info and that part of code is triggered and it is but for some reason this part is not working:
[[NSNotificationCenter defaultCenter] postNotificationName:#"openNews" object:nil userInfo:userInfo];
but Im using same method and everywhere and it works fine
That won't work because you are posting a notification with no one to catch it yet.
Hmm, what you can do here is to set the initial ViewController of your application when it receives the launchOptions you specified.
You can set it using this:
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"YourStoryboard" bundle:nil];
UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"YourStoryboardId"];
self.window.rootViewController = viewController;
[self.window makeKeyAndVisible];
Be careful though in designing your navigations. Especially if you want your initial ViewController to be a page with back button that access the navigation stack.
Since you will make it your initial view controller, if it tries to popViewController, it will pop to nothing.
EDIT:
If you want it to be opened from the MainVC with a delay, you can put tnis in your MainVC
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(openAnotherVC:)
name:#"YourPostNotificationName" object:nil];
Then navigate to your desired VC in openAnotherVC: method
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.
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~