didFinishLaunchingWithOptions APNS when app is close - ios

I am trying to connect notifications when the app is closed. I need to get a message from APNS and open the desired article by id. The problem is that the message is not read by APNS inside the function didFinishLaunchingWithOptions. I do not know where the mistake. I'm trying to parse (NSDictionary *) launchOptions and pull out the id of the article. Inside the function - didReceiveRemoteNotification everything works fine.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self settingMenuNotification];
[self restKitConfiguration];
[self registerSettingsAndCategories];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSLog(#"%#",[paths objectAtIndex:0]);
if(launchOptions != NULL) {
NSDictionary *userInfo = [launchOptions valueForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
NSDictionary *apsInfo = [userInfo objectForKey:#"aps"];
[self openNewsDetailNotification:apsInfo];
}
return YES;
}
-(void) openNewsDetailNotification:(NSDictionary*)apsInfo {
if( [apsInfo objectForKey:#"id"] != NULL) { //id - id_article
NSString *id_article = [apsInfo objectForKey:#"id"];
NSNumber *objectId = [NSNumber numberWithInteger: [id_article integerValue]];
NSLog(#"Получил id %#", id_article);
// Загружаем статью
UIWindow *window=[UIApplication sharedApplication].keyWindow;
UIViewController *root = [window rootViewController];
UIStoryboard *storyboard = root.storyboard;
NewsDetailViewController *newsVC = (NewsDetailViewController*)[storyboard instantiateViewControllerWithIdentifier:#"NewsDetailViewController"];
newsVC.objectId = objectId;
UINavigationController *navController = (UINavigationController *)self.window.rootViewController;
[navController.visibleViewController.navigationController pushViewController:newsVC animated:YES];
}
}

Same happened with me.I had added delay in that.Use this code instead of directly calling the function.
[self performSelector:#selector(openNewsDetailNotification:) withObject:apsInfo afterDelay:6.0f];

Related

If the application is closed and i receive the push notification, how detect the tap on notification and go to a specific controller?

I have an iOS application in which I am using the push notification to notify the user when the correct answer is posted. If the application is open and if I click on the notification it goes to the specified controller. But if the application is closed and if I receive the notification it does not goes to the specified controller.
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
NSLog(#"User Info %#",userInfo);
NSString* alertValue = [[userInfo valueForKey:#"aps"] valueForKey:#"badge"];
NSLog(#"my message-- %#",alertValue);
int badgeValue= [alertValue intValue];
// NSNumber *identifierString = [[[userInfo valueForKey:#"aps"]valueForKey:#"details"]valueForKey:#"identifire"];
// NSLog(#"identifierString %#",identifierString);
NSString *alertMessage = [[userInfo valueForKey:#"aps"] valueForKey:#"alert"];
NSLog(#"ALertMessage %#",alertMessage);
if ([alertMessage isEqualToString:#"New answer added."]) {
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:badgeValue];
// [[NSUserDefaults standardUserDefaults] setObject:[[[[userInfo valueForKey:#"aps"] valueForKey:#"details"] objectAtIndex:0]valueForKey:#"question"]forKey:#"notificationQuestion"];
// [[NSUserDefaults standardUserDefaults] setObject:[[[[userInfo valueForKey:#"aps"] valueForKey:#"details"] objectAtIndex:0]valueForKey:#"user_image"]forKey:#"notificationImage"];
// NSLog(#"Image %#",[[NSUserDefaults standardUserDefaults]valueForKey:#"notificationQuestion"]);
NSLog(#"User Information %#",userInfo);
NSLog(#"User Details %#",[[userInfo valueForKey:#"aps"] valueForKey:#"details"]);
// NSLog(#"User Details 1%#",[[[userInfo valueForKey:#"aps"] valueForKey:#"details"] objectAtIndex:0]);
// NSLog(#"User Details 1%#",[[[[userInfo valueForKey:#"aps"] valueForKey:#"details"] objectAtIndex:0]valueForKey:#"question"]);
pushDictonary = [[userInfo valueForKey:#"aps"] valueForKey:#"details"];
}
//NSArray *pushDetails = [[userInfo valueForKey:#"aps"] valueForKey:#"details"];
// NSLog(#"Push Details %#",pushDetails);
if (application.applicationState == UIApplicationStateActive ) {
// UILocalNotification *localNotification = [[UILocalNotification alloc] init];
// localNotification.userInfo = userInfo;
// localNotification.soundName = UILocalNotificationDefaultSoundName;
// localNotification.alertBody = [[userInfo valueForKey:#"aps"] valueForKey:#"alert"];
// localNotification.fireDate = [NSDate date];
if ([alertMessage isEqualToString:#"New answer added."])
{
[self createNotificationViewwithUserDictionary:userInfo];
}
}
else if (application.applicationState == UIApplicationStateBackground)
{
NSLog(#"YES");
}
else if (application.applicationState == UIApplicationStateInactive)
{
NSLog(#"YES");
if ([alertMessage isEqualToString:#"New answer added."])
[self pushdetailsViewController];
}
For going to the controller :
-(void)pushdetailsViewController
{
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
QPYourQuestionController *controller = (QPYourQuestionController*)[mainStoryboard instantiateViewControllerWithIdentifier: #"yourQuestion"];
[[QPCommonClass initializeUserDefaults]setObject:[pushDictonary valueForKey:#"question_id"] forKey:#"currentquestionID"];
NSLog(#"Dictionary %#",pushDictonary);
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
[navigationController pushViewController:controller animated:YES];
}
For the situation when application is closed the remote notification delegate
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
is not called
In this case the call goes to the following method:
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
Hence you can do this to take the user to the VC you want
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// ...
if (launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]) {
// Do whatever you want
}
}
add this code to your app delegate file
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
//you will get notification data in userInfo dict
UIStoryboard * mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
notificationViewController * notificationVC = [mainStoryboard instantiateViewControllerWithIdentifier: #"notificationViewController"];//set your controller here
[(UINavigationController *)self.window.rootViewController pushViewController:notificationVC animated:YES];
completionHandler(UIBackgroundFetchResultNewData);
}

iOS: App opens view life cycle methods are not called if app was in background

I want to open specific view controller if user opens app from url. But i am facing the problem, if user tap on home button and open app through URL, App opens in its last state because view life cycle methods are not called. Therefore, I am unable to navigate the view to task detail screen. I want, if user open app through url if it is in background then it should open the specific View controller.
PS: I cant terminate the app.
Following code i am using (code is written in AppDelegate.m):
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
if([UserName length]!=0 && [Password length]!=0)
{
NSLog(#"url recieved: %#", url);
NSLog(#"query string: %#", [url query]);
NSLog(#"host: %#", [url host]);
NSLog(#"url path: %#", [url path]);
// NSDictionary *dict = [self parseQueryString:[url query]];
// NSLog(#"query dict: %#", dict);
NSArray* query = [[url query] componentsSeparatedByString: #"&"];
NSString *taskId = [query objectAtIndex: 0];
NSString *taskType = [query objectAtIndex: 1];
NSArray* taskIdArray= [taskId componentsSeparatedByString: #"="];
NSArray* taskTypeArray = [taskType componentsSeparatedByString: #"="];
taskId = [taskIdArray objectAtIndex: 1];
taskType = [taskTypeArray objectAtIndex: 1];
NSLog(#"%#,%#",taskId,taskType);
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:[NSBundle mainBundle]];
ActivityDetailController *destViewController = (ActivityDetailController*)[storyboard instantiateViewControllerWithIdentifier:#"ActivityDetailView"];
[self.navigationController pushViewController:destViewController animated:YES];
}
return YES;
}
If you want to open app every time at ActivityDetailController when come to foreground then you can do this,
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:[NSBundle mainBundle]];
ActivityDetailController *destViewController = (ActivityDetailController*)[storyboard instantiateViewControllerWithIdentifier:#"ActivityDetailView"];
[self.navigationController pushViewController:destViewController animated:YES];
}
in applicationWillEnterForeground or applicationDidBecomeActive

How to manage openUrl method inside called application in iOS?

I suppose that this is duplicate but I can not figure it out.
I have to call other app from my iOS app using openUrl method. After finishing its work the other app must return to my app using the same method. I figure out how to call the other App and its open my App too. My problem is how to intercept the return to my App. I need to check the value from query string.
I find that method handleOpenURL intercepts return and I can handle my query string.
And here I am stuck - how to use that info inside my ViewController? I set breakpoint in viewDidLoad but it was not hit. Which method I have to use?
EDIT:
My Code is (inside AppDelegate):
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
NSLog(#"url recieved: %#", url);
NSLog(#"query string: %#", [url query]);
NSLog(#"host: %#", [url host]);
NSLog(#"url path: %#", [url path]);
NSDictionary *dict = [self parseQueryString:[url query]];
NSLog(#"query dict: %#", dict);
return YES;
}
- (NSDictionary *)parseQueryString:(NSString *)query {
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:6];
NSArray *pairs = [query componentsSeparatedByString:#"&"];
for (NSString *pair in pairs) {
NSArray *elements = [pair componentsSeparatedByString:#"="];
NSString *key = [[elements objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *val = [[elements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[dict setObject:val forKey:key];
}
return dict;
}
Which works fine.
Inside my ViewController (VC):
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self setNeedsStatusBarAppearanceUpdate];
// Instantiate App singleton
singApp = [PESsingApplication sharedInstance];
#try {
// Localize resources using currently saved setting for language
[self setLocalizedResources];
// Init visual buttons
[self baseInit];
// Add code for keyboard management
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardHide:)
name:UIKeyboardWillHideNotification
object:nil];
CGRect screenRect = [[UIScreen mainScreen] bounds];
_screenHeight = screenRect.size.height;
_screenWidth = screenRect.size.width;
}
#catch (NSException *exception) {
[self throwUnknownException:exception];
}
}
-(UIStatusBarStyle)preferredStatusBarStyle{
return UIStatusBarStyleLightContent;
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
My url:
URL identifier: xx.mydomain.MyUrlScheme
URL shcemes: MyUrlScheme
I have breakpoints inside my VC (on each of the method shown above).
I use following string to call other app: #"otherApp://openApp?param1=value1&callbackUrl=MyUrlScheme";
They call me from the otherApp using callbackUrl param.
You need to make your own custom URL, please look below
How to implement Custom URL Scheme
Defining your app's custom URL scheme is all done in the Info.plist file. Click on the last line in the file and then click the "+" sign off to the right to add a new line. Select URL Types for the new item. Once that's added, click the grey arrow next to "URL Types" to show "Item 0". Set your URL identifier to a unique string - something like com.yourcompany.yourappname.
After you've set the URL identifier, select that line and click the "+" sign again, and add a new item for URL Schemes. Then click the grey arrow next to "URL Schemes" to reveal "Item 0". Set the value for Item 0 to be your URL scheme name.
Handling Custom URL Calls
In order for your app to respond when it receives a custom URL call, you must implement the application:handleOpenURL method in the application delegate class:
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
// your code
}
Parsing the Custom URL
There are several parts to a URL:
scheme://host/path?query
The parts to the URL can be retrieved through the NSURL object that is passed into the application:handleOpenURL method. If you have a fairly simple URL naming scheme and want to allow access to specific pages/keys, you can just use the host name:
Custom URL Value of [url host]:
myapp://page1 page1
myapp://page2 page2
myapp://otherPage otherPage
To pass data into your app, you'll want to use the query string. Here's a simple method for parsing the query string from the url:
- (NSDictionary *)parseQueryString:(NSString *)query {
NSMutableDictionary *dict = [[[NSMutableDictionary alloc] initWithCapacity:6] autorelease];
NSArray *pairs = [query componentsSeparatedByString:#"&"];
for (NSString *pair in pairs) {
NSArray *elements = [pair componentsSeparatedByString:#"="];
NSString *key = [[elements objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *val = [[elements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[dict setObject:val forKey:key];
}
return dict;
}
Testing The Custom URL
You can easily test your URL scheme in the simulator. Just add a test button to one of your views, and implement the IBAction method for it as follows:
- (IBAction)getTest:(id)sender {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"myappscheme://test_page/one?token=12345&domain=foo.com"]];
}
Then in your app delegate, implement the application:handleOpenURL method:
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
NSLog(#"url recieved: %#", url);
NSLog(#"query string: %#", [url query]);
NSLog(#"host: %#", [url host]);
NSLog(#"url path: %#", [url path]);
NSDictionary *dict = [self parseQueryString:[url query]];
NSLog(#"query dict: %#", dict);
return YES;
}
Finally if you are looking method to receive your data anywhere you can use this two scenario.
You can simple use Local notification or NSUserDefault
NSUserDefault
- (BOOL)application:(UIApplication *)application handleopenURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
NSUserDefaults *userDefaults=[[NSUserDefaults alloc] init];
[userDefaults synchronize];
NSString *status = [defaults stringForKey:#"any status"];
}
Local notification
- (BOOL)application:(UIApplication *)application handleopenURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif == nil)
return;
localNotif.userInfo = [NSDictionary dictionaryWithObjectsAndKeys:VAL, #"value", nil];
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
}
If your viewDidLoad is not called perfectly try in viewWillAppear or viewDidAppear method.
For example purpose:
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
NSDictionary *dict = [self parseQueryString:[url query]];
NSLog(#"query dict: %#", dict);
// add dictionary to standardUserDefaults for saving purpose, like
[[NSUserDefaults standardUserDefaults] setObject:dict forKey:#"DicKey"];
[[NSUserDefaults standardUserDefaults] synchronize];
// add code for navigation/present view controller
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main"
bundle: nil];
YourViewController *yourController = (YourViewController *)[mainStoryboard
instantiateViewControllerWithIdentifier:#"YourViewControllerID"];
self.window.rootViewController = yourController;
return YES;
}
for retrieve
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSMutableDictionary *mutableRetrievedDictionary = [[[NSUserDefaults standardUserDefaults] objectForKey:#"DicKey"] mutableCopy];
// here parse the dictionary and do your work here, when your works is over
// remove the key of standardUserDefaults
[[NSUserDefaults standardUserDefaults] removeObjectForKey:#"DicKey"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
Store the status from other app in NSUserdefaults, when the ViewController of your app launches fetch the status into a NSString from NSUserdefaults and rise it as an alert.
Call the handleopenURL in appdelegate
- (BOOL)application:(UIApplication *)application handleopenURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
NSUserDefaults *defaults=[[NSUserDefaults alloc] init];
[defaults synchronize];
NSString *status = [defaults stringForKey:#"status string from other app"];
}

Handling multiple push notifications got error

I handle push notification when the screen is on by automatically push to a detailViewController. It works fine when there is one or two push notification as I can push each detailViewController on top of each other and pop it back. However, app crash when I have to pop back more than two detailViewControllers. It happens only in iOS 7+.
Set notification Id
- (void)application:(UIApplication *)app didReceiveRemoteNotification:(NSDictionary *)userInfo
{
if(app.applicationIconBadgeNumber!=0)
{
app.applicationIconBadgeNumber = app.applicationIconBadgeNumber - 1;
}
NSString *aps =[NSString stringWithFormat:#"%#",[userInfo objectForKey:#"id"]];
if (app.applicationState == UIApplicationStateActive)
{
NSDictionary *dict = [NSDictionary dictionaryWithObjects:#[[[userInfo objectForKey:#"aps"] objectForKey:#"alert"]] forKeys:#[#"notifyText"]];
[arrNotificationData addObject:dict];
[self showNotificationInActiveMode:[[userInfo objectForKey:#"aps"] objectForKey:#"alert"]];
}
if ([aps isEqualToString:#"1"])
{
[UserDefault setpushnotificationid:[aps intValue]];
}
if ([aps isEqualToString:#"2"])
{
[UserDefault setpushnotificationid:[aps intValue]];
}
if ([aps isEqualToString:#"3"])
{
[UserDefault setpushnotificationid:[aps intValue]];
}
if ([aps isEqualToString:#"4"])
{
[UserDefault setpushnotificationid:[aps intValue]];
}if ([aps isEqualToString:#"5"])
{
[UserDefault setpushnotificationid:[aps intValue]];
}
}
Use singleton class as base class and check for ID and the push and pop the view.
#interface CustomViewController ()
#end
#implementation CustomViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter]addObserver:self
selector:#selector(appBecomeActive)
name:UIApplicationDidBecomeActiveNotification
object:nil];
}
-(void)appBecomeActive
{
int val=[UserDefault getpushnotificationid];
if(val!=0){
[self checkforpushnotification];
}
}
-(void)checkforpushnotification
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
int val=[UserDefault getpushnotificationid];
[UserDefault setpushnotificationid:0];
//.: if current view is profile or setting just dismiss it.because they are present
switch (val)
{
case 1:
{
if( [self checkIfControllerExist:[DealsViewController class]])
{
return;
}else{
detailViewController *VC = (detailViewController *)[storyboard instantiateViewControllerWithIdentifier:#"VCView"];
[self.navigationController pushViewController:VC animated:YES];
}
}
break;
}
}
Now use bace class in your class
#interface detailViewController : CustomViewController

Copying NSDictionary to NSMutable Dictionary doesn't work?

I am trying to copy the contents of one NSDictionary into a NSMutableDictionary.
This is what I have done so far.
#implementation RosterListController
- (void)newMessageReceived:(NSDictionary *)messageContent
{
self.messageDictionary = [[NSMutableDictionary alloc]initWithDictionary:messageContent]; // This is where I am copying
UIApplication *app = [UIApplication sharedApplication];
if (app.applicationState == UIApplicationStateActive)
{
UILocalNotification *localNotif = [[UILocalNotification alloc]init];
if (localNotif)
{
localNotif.alertAction = #"OK";
localNotif.applicationIconBadgeNumber = [[UIApplication sharedApplication] applicationIconBadgeNumber] + 1;
[app presentLocalNotificationNow:localNotif];
}
}
}
Then I handle this notification in appDelegate by showing a AlertView.After that is done..coming back to RosterViewController.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0) {
NSLog(#"Cancel button presed");
}
else
{
if(chatView) // Chat ViewController
{
[chatView recvdMsg:self.messageDictionary];
}
else
{
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard"
bundle: nil];
chatView=(ChatViewController *)[mainStoryboard instantiateViewControllerWithIdentifier:#"chatviewcontroller"];
NSMutableDictionary *buddy=[[NSMutableDictionary alloc]init];
// The break point stops the app here & shows buddy dictionary as nil.
==> [buddy setObject:[self.messageDictionary objectForKey:#"sender"] forKey:#"jid"];
// Originally it was messageContent dict from the parameter above that I used which worked fine..
//But since I need that dictionary in another method..I copied that dictionary into self.messageDictionary which also gets copied.
// However now the above line causes problems.
// [buddy setObject:[self.messageContent objectForKey:#"sender"] forKey:#"jid"];
chatView.buddyData=buddy;
[self.navigationController pushViewController:chatView animated:YES];
[chatView recvdMsg:self.messageDictionary];
}
}
}
To create NSMutableDictionary from NSDictionary you should use dictionaryWithDictionary which is declared in NSDictionary.h.
NSMutableDictionary *aMutDictFromAnotherDictionary = [NSMutableDictionary dictionaryWithDictionary:YOUR_NSDICTIONARY_OBJECT];

Resources