Handling Push Notification on iOS - ios

Currently I'm working on handling push notification and I get bug when the first notification success received and shows me the destination view controller. But for the second and the rest the application crash. I get the problem is the app doesn't receive the parameter that should get from push notification.
AppDelegate.m
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
//[PFPush handlePush:userInfo];
NSLog(#"didReceiveRemoteNotification userInfo=%#", userInfo);
if(application.applicationState == UIApplicationStateActive)
{
NSDictionary *aps = userInfo[#"aps"];
NSString *alertTitle = #"";
if([userInfo[#"page"] isEqualToString:#"ga"])
{
alertTitle = #"General Advisory";
}
else if ([userInfo[#"page"] isEqualToString:#"cr"])
{
alertTitle = #"Customer Recommendation";
}
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:alertTitle
message:[aps objectForKey:#"alert"]
delegate:self
cancelButtonTitle:#"Close"
otherButtonTitles:nil];
[alert addButtonWithTitle:#"View"];
//set tag to id
alert.tag = [userInfo[#"id"] intValue];
[alert show];
}
else if(application.applicationState == UIApplicationStateInactive)
{
[self movePageAfterReceiveNotification:userInfo[#"page"] withId:userInfo[#"id"]];
}
}
- (void)movePageAfterReceiveNotification:(NSString *)page withId:(NSString *)pageId
{
UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
UITabBarController *tabBarVC = (UITabBarController*)topController.presentedViewController;
if (tabBarVC.selectedIndex > 0)
{
[tabBarVC setSelectedIndex:0];
}
UINavigationController *navcon = (UINavigationController*)[tabBarVC.viewControllers firstObject];
HomeViewController *homeVC = (HomeViewController*)[navcon topViewController];
NSLog(#"Page: %#",page);
NSLog(#"ID: %#",pageId);
if ([page isEqualToString:#"ga"])
{
//redirect to homeVC
[homeVC loadDataGeneralAdvisoryFromPushNotif:pageId];
}
else if ([page isEqualToString:#"cr"])
{
//redirect to homeVC
[homeVC loadDataCustomerRecommendationFromPushNotif:pageId];
}
}
The error like this:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[CRDetailViewController loadDataCustomerRecommendationFromPushNotif:]: unrecognized selector sent to instance 0x14756d180'

The topViewController of your first navigation controller (tab one) is not HomeViewControlled but CRDetailViewController. As you can see the error message says '-[CRDetailViewController loadDataCustomerRecommendationFromPushNotif:]: unrecognized selector sent to instance 0x14756d180'
You probably want your HomeViewController to handle that information, because that view controller is the one implementing your loadDataCustomerRecommendationFromPushNotif method.
I guess you should call [navcon popToRootViewControllerAnimated:NO] right before HomeViewController *homeVC = (HomeViewController*)[navcon topViewController];
Something like this, probably:
UINavigationController *navcon = (UINavigationController*)[tabBarVC.viewControllers firstObject];
[navcon popToRootViewControllerAnimated:NO]
HomeViewController *homeVC = (HomeViewController*)[navcon topViewController];

Related

How to handle Remote push notifications in didreceiveRemoteNotification in AppDelegate

For my Remote push notifications I have handle like this in my AppDelegate
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
dm=[DataManager sharedManager];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
dm.screenHight=[UIScreen mainScreen].bounds.size.height;
dm.screenWidth=[UIScreen mainScreen].bounds.size.width;
NSLog(#"^^^^^^^^^^^^^^ Screen hight ^^^^^^^^^^^^^ %i",dm.screenHight);
// for PAYPAL
[PayPalMobile initializeWithClientIdsForEnvironments:#{PayPalEnvironmentProduction : #"YOUR_CLIENT_ID_FOR_PRODUCTION",PayPalEnvironmentSandbox : #"AQhrXRAyHg6nuJCma6vkl1ZtxmWUynzuf2temitMSJEZf8n74p9iKAt6TgSf"}];
/// FOR PAYPAL
NSLog(#"%#",userInfo);
NSDictionary *dictionary=[userInfo objectForKey:#"jsonContent"];
dm.notificationDictionary=dictionary;
if ( application.applicationState == UIApplicationStateActive )
{
UIViewController *viewController1;
viewController1 = [[SplashViewController alloc] initWithNibName:#"SplashViewController" bundle:nil];
UINavigationController *aNavigationController=[[UINavigationController alloc] initWithRootViewController:viewController1];
self.navigationcontroller = aNavigationController ;
self.navigationcontroller.navigationBar.hidden=YES;
[self.window setRootViewController:self.navigationcontroller];
[self.window makeKeyAndVisible];
}
else
{
UIViewController *viewController1;
viewController1 = [[SplashViewController alloc] initWithNibName:#"SplashViewController" bundle:nil];
UINavigationController *aNavigationController=[[UINavigationController alloc] initWithRootViewController:viewController1];
self.navigationcontroller = aNavigationController ;
self.navigationcontroller.navigationBar.hidden=YES;
//[self.window addSubview:[self.navigationcontroller view]];
//[self.window setRootViewController:viewController1];
[self.window setRootViewController:self.navigationcontroller];
[self.window makeKeyAndVisible];
}
}
This is working fine. But my problem is when the app is in active state its automatically redirect to the relavent page before click the notification. But I want to keep the apps current screen as it is when it is in the forground and when only user clk the notification redirect to the relavant page. How can I do this? Please help me.
Thanks
If your app is in active state, you can show your notification details in a UIAlertView. User will perform the action through the alert. But you cannot expect the notification in this state.
UIApplicationState appState = [application applicationState];
if (appState == UIApplicationStateActive) {
NSString *cancelTitle = #"Close";
NSString *showTitle = #"Show";
NSString *message = [[userInfo valueForKey:#"aps"] valueForKey:#"alert"];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#“Your Title”
message:message
delegate:self
cancelButtonTitle:cancelTitle
otherButtonTitles:showTitle, nil];
[alertView show];
return;
}

Display an Alert popup when application is receiving an Apple Push Notification in iOS

I am creating a Chat kind of iPhone application using Apple push notification services. APN's is working fine and i am getting notification when user is receiving new message. So, i have set one Toast pop up in didReceiveRemoteNotification of my App Delegate class. The problem is, i am getting Toast pop up in every View Controller screen because i have added Toast on my main window itself. but can you please help me that how can i hide this Toast pop up from one of my Chat List View Controller screen. How can i check which View Controller is loaded currently on my window view, when application is in foreground?
here is my code :
- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo
{
if ( application.applicationState == UIApplicationStateActive ){
NSString *personName = [[userInfo valueForKey:#"aps"] valueForKey:#"user_name"];
NSString *meassge = [NSString stringWithFormat:#"New message from %#.", personName];
[[self window] makeToast:meassge duration:1.0 position:#"center"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"reloadTheTable" object:nil];
}
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
[[UIApplication sharedApplication] cancelAllLocalNotifications];
}
Thanks!
Declare below methods in AppDelegate.m
- (UIViewController*)topViewController {
return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}
- (UIViewController*)topViewControllerWithRootViewController:(UIViewController*)rootViewController {
if ([rootViewController isKindOfClass:[UITabBarController class]]) {
UITabBarController* tabBarController = (UITabBarController*)rootViewController;
return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
} else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController* navigationController = (UINavigationController*)rootViewController;
return [self topViewControllerWithRootViewController:navigationController.visibleViewController];
} else if (rootViewController.presentedViewController) {
UIViewController* presentedViewController = rootViewController.presentedViewController;
return [self topViewControllerWithRootViewController:presentedViewController];
} else {
return rootViewController;
}
}
- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo
{
if ( application.applicationState == UIApplicationStateActive ){
NSString *personName = [[userInfo valueForKey:#"aps"] valueForKey:#"user_name"];
NSString *meassge = [NSString stringWithFormat:#"New message from %#.", personName];
if(![[self topViewController] isKindOfClass:[ChatListViewController class]])//ChatListViewController is your viewcontroller
[[self window] makeToast:meassge duration:1.0 position:#"center"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"reloadTheTable" object:nil];
}
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
[[UIApplication sharedApplication] cancelAllLocalNotifications];
}

Error presentViewController - view controllers adding - objective c

I have a problem and can't know the reason or solution
I have AddDelegate and another ViewController, in this ViewController I add FBFriendPickerViewController, and ViewController will be added to AppDelegate ..
I add ViewController to AppDelegate like this: ( this ViewController is SocialSharing class )
if( socialSharing == nil )
socialSharing = [[SocialSharing alloc] init];
[_window.rootViewController.view addSubview:socialSharing.view];
And add FBFriendPickerViewController in ViewController(SocialSharing) like this:
-(void)shareOnFaceBook:(NSNotification *) notification
{
if( shareOnUserOrFriendWallBtnIndex == 0 )
{
if([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) {
SLComposeViewController *facebookSheet = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
NSURL *candidateURL = [NSURL URLWithString:contentDataToShare];
if (candidateURL && candidateURL.scheme && candidateURL.host) {
[facebookSheet setInitialText:#"See this link .."];
[facebookSheet addURL:candidateURL];
}
else // Event ***
{
[facebookSheet setInitialText:[NSString stringWithFormat:#"%#%#%#",[[appDelegate.extrasOverlayView.markerData.btnsArr objectAtIndex:0] objectForKey:#"markerName"],#" .. \n", contentDataToShare]];
[facebookSheet addURL:[NSURL URLWithString:lastVideoLink]];
}
//Brings up the little share card with the test we have pre defind.
[appDelegate.window.rootViewController presentViewController:facebookSheet animated:YES completion:nil];
} else {
//This alreat tells the user that they can't use built in socal interegration and why they can't.
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Sorry" message:#"You can't send a tweet right now, make sure you have at least one Facebook account setup and your device is using iOS." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
}
else if( shareOnUserOrFriendWallBtnIndex == 1 )// post on friend's wall
{
if ( [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:#"fb://"]] )
{
NSLog(#"Facebook is inastalled on this device.");
if( friendPickerController == nil )
{
friendPickerController = [[FBFriendPickerViewController alloc] init];
friendPickerController.delegate = self;
if( !( [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone ) )
friendPickerController.title = #"Select Friends";
}
[friendPickerController loadData];
// Present view controller modally
[self presentViewController:friendPickerController animated:YES completion:nil];
}
else{
NSLog(#"This device has no Facebook app.");
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Sorry" message:#"You can't invite friends, Facebook app isn't installed, please install it and retry again." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
}
}
and dismiss friendPickerController from SocialSharing like:
- (void)facebookViewControllerCancelWasPressed:(id)sender
{
NSLog(#"Friend selection cancelled.");
[self dismissViewControllerAnimated:YES completion:nil];
}
I used:
[friendPickerController dismissModalViewControllerAnimated:YES];
OR //[self.view.window.rootViewController dismissViewControllerAnimated:YES completion:Nil];
OR //[self dismissModalViewControllerAnimated:YES];
It works good for only first time, once, friendPickerController appears and dismiss when close, BUT when call to open again, I have this error:
"Thread 1: signal SIGBRT"
FOR the line of :
[self presentViewController:friendPickerController animated:YES completion:nil];
Note: when I add friendPickerController on AppDelegate directly (in class of AppDelegate) without another class (here is SocialSharing ViewController), it works great ..
I'm working on IOS 7, and Facebook SDK 3.13..
So, What is the problem, How can I solve it ?
Thank you
What I did to solve my problem, I create friendPickerController in NORMAL CLASS , NOT ViewController, and add it on AppDelegate
[appDelegate.window.rootViewController presentViewController:friendPickerController animated:YES completion:nil];
and dismiss by:
[appDelegate.window.rootViewController dismissViewControllerAnimated:YES completion:nil];
And call this Class like:
if( socialSharing == nil )
{
socialSharing = [[SocialSharingClass alloc] init];
[socialSharing initSocialSharing];
}
Still, I don't know the problem, but that solved it. May that help anyone.

FBSession: should only be used from a single thread

I'm developing an app for FB wall posting in ios using facebook sdk 3.5. I'm using two views. Firts one is a splash screen and a second one is the facebook login view. When i'm activate both views I'm getting a thread and error displayed,
2013-05-17 17:07:59.115 [415:12503] * Assertion failure in -[FBSession checkThreadAffinity], /Users/chrisp/tmp/sdk/ios-sdk/src/FBSession.m:1571
2013-05-17 17:07:59.127 [415:12503] * Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'FBSession: should only be used from a single thread'
* First throw call stack:
(0x2387052 0x1fa3d0a 0x232fa78 0x1a9c2db 0x21fa2 0x1e626 0x1ecd9 0x22b67 0x1eba3 0x3c265 0x2388ec9 0x11165c2 0x111655a 0x11bbb76 0x11bc03f 0x11bb2fe 0x113ba30 0x113bc56 0x1122384 0x1115aa9 0x293ffa9 0x235b1c5 0x22c0022 0x22be90a 0x22bddb4 0x22bdccb 0x293e879 0x293e93e 0x1113a9b 0x2be2 0x2b15)
terminate called throwing an exception(lldb)
Here is my Appdelegate.m code,
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]autorelease];
// Override point for customization after application launch.
self.viewController = [[[SplashViewController alloc] initWithNibName:#"SplashViewController" bundle:nil]autorelease] ;
// self.loginViewController = [[secondview alloc] initWithNibName:#"secondview"
// bundle:nil];
// self.navigationController = [[UINavigationController alloc] initWithRootViewController:self.loginViewController];
// self.navigationController.delegate = self;
// self.window.rootViewController = self.navigationController;
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
//
//
UIBackgroundTaskIdentifier backgroundTask = [application beginBackgroundTaskWithExpirationHandler:^{NSLog(#"BackgroundTask Expiration Handler is called");
[application endBackgroundTask:backgroundTask];
}];
And this is the facebook_view.m code
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.navigationController.navigationBarHidden = YES;
}
- (void)viewWillDisappear:(BOOL)animated {
self.navigationController.navigationBarHidden = NO;
}
- (void)viewDidUnload {
[self setFBLoginView:nil];
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - FBLoginView delegate
- (void)loginViewShowingLoggedInUser:(FBLoginView *)loginView {
// Upon login, transition to the main UI by pushing it onto the navigation stack.
TNLRadioAppDelegate *appDelegate = (TNLRadioAppDelegate *)[UIApplication sharedApplication].delegate;
[self.navigationController pushViewController:((UIViewController *)appDelegate.viewController) animated:YES];
}
- (void)loginView:(FBLoginView *)loginView
handleError:(NSError *)error{
NSString *alertMessage = nil, *alertTitle;
// Facebook SDK * error handling *
// Error handling is an important part of providing a good user experience.
// Since this sample uses the FBLoginView, this delegate will respond to
// login failures, or other failures that have closed the session (such
// as a token becoming invalid). Please see the [- postOpenGraphAction:]
// and [- requestPermissionAndPost] on `SCViewController` for further
// error handling on other operations.
if (error.fberrorShouldNotifyUser) {
// If the SDK has a message for the user, surface it. This conveniently
// handles cases like password change or iOS6 app slider state.
alertTitle = #"Something Went Wrong";
alertMessage = error.fberrorUserMessage;
} else if (error.fberrorCategory == FBErrorCategoryAuthenticationReopenSession) {
// It is important to handle session closures as mentioned. You can inspect
// the error for more context but this sample generically notifies the user.
alertTitle = #"Session Error";
alertMessage = #"Your current session is no longer valid. Please log in again.";
} else if (error.fberrorCategory ==
FBErrorCategoryUserCancelled) {
// The user has cancelled a login. You can inspect the error
// for more context. For this sample, we will simply ignore it.
NSLog(#"user cancelled login");
} else {
// For simplicity, this sample treats other errors blindly, but you should
// refer to https://developers.facebook.com/docs/technical-guides/iossdk/errors/ for more information.
alertTitle = #"Unknown Error";
alertMessage = #"Error. Please try again later.";
NSLog(#"Unexpected error:%#", error);
}
if (alertMessage) {
[[[UIAlertView alloc] initWithTitle:alertTitle
message:alertMessage
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil] show];
}
}
- (void)loginViewShowingLoggedOutUser:(FBLoginView *)loginView {
// Facebook SDK * login flow *
// It is important to always handle session closure because it can happen
// externally; for example, if the current session's access token becomes
// invalid. For this sample, we simply pop back to the landing page.
TNLRadioAppDelegate *appDelegate = (TNLRadioAppDelegate *)[UIApplication sharedApplication].delegate;
if (appDelegate.isNavigating) {
// The delay is for the edge case where a session is immediately closed after
// logging in and our navigation controller is still animating a push.
[self performSelector:#selector(logOut) withObject:nil afterDelay:.5];
} else {
[self logOut];
}
}
- (void)logOut {
[self.navigationController popToRootViewControllerAnimated:YES];
}
Cqan any one help???
It sounds like you're accessing your FBSession instance from more than one thread. Check that you're not calling [FBSession activeSession] or anything similar from a background thread (or that you're always calling it from the same background thread).

Run a function after push notification

I'm developing an iOS app for iPad. I'm using Push notifications with a service called HelpShift. I'd like to run a piece of code when the users taps the notification. It actually works when the app is active, but when it's background or inactive, it doesn't work. Here is my code:
- (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
if ([[userInfo objectForKey:#"origin"] isEqualToString:#"helpshift"]) {
UIApplicationState state = [application applicationState];
if (state == UIApplicationStateActive) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"You were answered in HelpShift"
message:#"Hello"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Show", nil];
[alertView show];
} if (state== UIApplicationStateBackground) {
UIViewController *vc = self.window.rootViewController;
[[Helpshift sharedInstance] handleNotification:userInfo withController:vc];
[self showHelpShift];
} if (state == UIApplicationStateInactive) {
UIViewController *viewController =
[[UIStoryboard storyboardWithName:#"MainStoryboard"
bundle:NULL] instantiateViewControllerWithIdentifier:#"home"];
[[Helpshift sharedInstance] handleNotification:userInfo withController:viewController];
}
}
}
- (void) showHelpShift {
UIViewController *vc = self.window.rootViewController;
[[Helpshift sharedInstance] showSupport:vc];
}
- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
if (buttonIndex == 1){
UIViewController *vc = self.window.rootViewController;
[[Helpshift sharedInstance] showSupport:vc];}
}
So as you can see, the problem is that the [self showHelpShift] doesn't get called or it gets called to early.
Implement application:didFinishLaunchingWithOptions: and look for the UIApplicationLaunchOptionsRemoteNotificationKey key in the launchOptions dictionary.

Resources