Performe, navigate, to child view from App Delegate - ios

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
}

Related

App is crashing while using SWRevealViewController

I am using SWRevealViewController for Slide Out Menu for an application in which slide out menu starts only from the Home Screen after Sign Up button is pressed in SignUp page(i.e. running the application for the first time).
When the app is running for the second time it is suppose to go directly to the Home Screen,but the app is crashing, and I am getting crash log in ViewController.
_barBtnMenu.target = self.revealViewController;
_barBtnMenu.action = #selector(revealToggle:);
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
NSInvalidArgumentException', reason:'-[__NSArrayM
insertObject:atIndex:]: object cannot be nil.
For app's first time run I am using Present Modally Segue from Sign Up button.
In SWRevealViewController
- (SWRevealViewController*)revealViewController
{
UIViewController *parent = self;
Class revealClass = [SWRevealViewController class];
while ( nil != (parent = [parent parentViewController]) && ![parent isKindOfClass:revealClass] ) {}
return (id)parent;
}
While running it for the first time
parent is returning a value but for the second run it is returning nil
If anyone could help me in solving the issue.
Thanks in advance.
EDIT
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSString *savedValue = [[NSUserDefaults standardUserDefaults]
stringForKey:#"email"];
if (savedValue != nil) {
UIStoryboard *storyboard = self.window.rootViewController.storyboard;
ViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"viewController"];
self.window.rootViewController =viewController;
[self.window makeKeyAndVisible];
} else {
NSLog(#"Sign Up screen opened");
}
return YES;
}
You are trying to implement Autologin feature in your app
for the second launch you have to maintain a flag in Appdelegate that user is already logged in or not , if user is already logged in you have to move to the parent controller of SWRevealview from didfinishlaunchingwithoptions function in app delegate.
for that save username and password to userdefaults at login & signup
check for values in didfinishlaunchingwithoptions
if value exist move to parent of SWrevealview
Thanks for the replies,
I solved it by making SignUp page as Root view
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSString *savedValue = [[NSUserDefaults standardUserDefaults]
stringForKey:#"email"];
if (savedValue == nil) {
UIStoryboard *storyboard = self.window.rootViewController.storyboard;
SignUpViewController *signUpViewController = [storyboard instantiateViewControllerWithIdentifier:#"signUpViewController"];
self.window.rootViewController = signUpViewController;
[self.window makeKeyAndVisible];
} else {
NSLog(#"Sign Up screen closed,Hom page opened");
}
return YES;
}

Open app through notification banner when app is not running state iOS

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 :)

iOS: Display notification message when application opens

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...

Open view controller when APNS is received in iOS

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.

Issue in open view controller when APNS is received in iOS

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~

Resources