iphone Launch Options - iphone

im not getting any launch options after a push notification; heres the code i have but non of the NSLogs seem to print in the debug area.
UILocalNotification *localNotif =
[launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (localNotif) {
NSString *itemName = [localNotif.userInfo objectForKey:#"aps"];
NSLog(#"Custom: %#", itemName);
} else {
NSLog(#"//////////////////////////");
}
when i open the app (via pressing view on the push notification) it goes to the didReceiveRemoteNotification script, im not sure if thats meant to happen..
thanks for reading.

Your application receives push notifications through multiple paths, depending on the state of your app when it is received.
If your app is not launched (not even suspended in background), the launchOptions will contain the notification payload (key UIApplicationLaunchOptionsRemoteNotificationKey).
If it is already running or suspended in background, the app will receive the notifications via application:didReceiveRemoteNotification: in your application delegate.
The process is the same for local notifications (UIApplicationLaunchOptionsLocalNotificationKey in application:didFinishLaunchingWithOptions: and application:didReceiveLocalNotification:)

an error spotted:
NSDictionary *remoteNotif = [launchOptions objectForKey:
UIApplicationLaunchOptionsRemoteNotificationKey];
If you want to receive the remote notification, NSDictionary should be used not UILocalNotification
The remote notification is a payload, containing arguments, not a local notification. You might want to look at this url question:
Crash when handling remote notification when app not running
If you want to do local notification, change it like Ludovic's suggestion

The answers given above are correct. I largely use the following snippet in my application:didFinishLaunchingWithOptions:
if let remoteNotifPayload = launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification] as? [AnyHashable: Any] {
notificationsController.didReceiveRemoteNotification(with: remoteNotifPayload)
}

If you want a local notification (I assume with your var name) replace UIApplicationLaunchOptionsRemoteNotificationKey by UIApplicationLaunchOptionsLocalNotificationKey and this should work.

(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
NSLog(#"Alert message: %#",[[userInfo valueForKey:#"aps"] valueForKey:#"alert"]);
}

You can use NSUserDefaults to do the trick. In your AppDeligate.m, set a bool to YES in the first time. So after that it never gets to NO.
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//add this if loop
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"HasLaunchedOnce"])
{
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"HasLaunchedOnce"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}

Related

How to determine if an app is returning from a phone call or resuming from background?

I make phone call from my application using:
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"telprompt://XXXXXXXXXX"]];
When the user ends the call, the default Apple-provided Phone app goes to the background and my application resumes focus. This happens automatically.
Now here's what I want: I'd like to call a method every time (and only when) the user returns from a call.
I tried calling this method from applicationWillEnterForeground: or applicationDidBecomeActive: but these callbacks are fired at other times when the application is being launched from the background state(which I dont want).
I'd like to determine if my application is being launched from the background state or if it is returning from a phone call so I can perform a certain task only in the former case and not latter. Any ideas?
----EDIT----
Here's how I finally did it:
See: CallStateDisconnected only detected for incoming calls, not for calls made from my app
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self listenForCalls];
}
- (void)listenForCalls {
self.callCenter = [[CTCallCenter alloc] init];
self.callCenter.callEventHandler = ^(CTCall* myCall) {
NSString *call = myCall.callState;
if([call isEqualToString:CTCallStateDialing]) {
//do ur stuff
}
};
}
You Can use telephony framework, Which provides you call states to determine the state of phone.
You can find out detail from here:
http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Reference/CTCall/Reference/Reference.html#//apple_ref/doc/uid/TP40009590
Why not save a flag indicating that your app sent the user to the phone call. When your applications becomes active, if the flag is set, do the return from phone call method.
ex.
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"DidStartPhoneCall"];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"telprompt://XXXXXXXXXX"]];
Then something like,
-(void)applicationDidBecomeActive {
BOOL activeFromCall = [[NSUserDefaults standardUserDefaults] objectForKey:"DidStartPhoneCall"]
if(activeFromCall && [activeFromCall boolValue] == YES) {
// do your method
}
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:#"DidStartPhoneCall"]; // reste flag
}

User taps on UILocalNotification: Can it pass data to the app?

I am creating a local UILocalNotification and displaying it to the user as a banner. Is it possible to set it up so that when the user taps it and returns to the app, the app will receive some kind of data on the specific kind of notification it was? I want to open a specific view controller in the app. I think the best way would be to essentially send a URL to the app, or is there a way to get access to the UILocalNotification so that I can test which kind is was and do the right action?
To get data from the local NSUserNotification that is passed to an iOS app, all that you need to do is implement the following method: - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification.
The problem is, this is called both when a local notification is posted when the app is in the background (i.e. when the user taps on the notification and then returns to the app), and also if the app is in the foreground at the time when the local notification fires (it is on a timer, after all). So how should one figure out if the notification was fired when the app was in the background or foreground? It's pretty simple. Here's my code:
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
UIApplicationState state = [application applicationState];
if (state == UIApplicationStateInactive) {
// Application was in the background when notification was delivered.
} else {
// App was running in the foreground. Perhaps
// show a UIAlertView to ask them what they want to do?
}
}
At this point you can handle the notification based on notification.userInfo, which holds a NSDictionary.
ust implement the NSUserNotificationCenterDelegate and define this method:
- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification
Example:
This is what I did in a "notifier" application.
- (void) userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification
{
NSRunAlertPanel([notification title], [notification informativeText], #"Ok", nil, nil);
}
- (void) userNotificationCenter:(NSUserNotificationCenter *)center didDeliverNotification:(NSUserNotification *)notification
{
notifications=nil;
[tableView reloadData];
[center removeDeliveredNotification: notification];
}
When the notification is activated (click by the user) I just inform the user with a panel (I could use a hud window).In this case I immediately remove the delivered notification, but this is not what happens usually.The notification could stay there some time and be removed after 1/2 hours (it depends on the application that you are developing).
1 - Define some class in your project to implement NSUserNoficationCenterDelegate protocol (documented here)
#interface someObject : NSObject <NSUserNotificationCenterDelegate>
{
- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification;
}
2 - Set an instance of the object defined #1 as the delegate of default notification center.
[[NSUserNotificationCenter defaultNotificationCenter] setDelegate: someObject];
Now you will get called on didActivateNotification any time the user taps/clicks on the notification. You will have the original notification you created. So any information that you need should be available to you.
If you want/need special information (other than notification title, message, etc) you will probably need to set additional application specific information in your notification before you schedule it to be sent. For example:
NSUserNotification* notification = [[NSUserNotification alloc] init];
NSDictionary* specialInformation = [NSDictionary dictionaryWithObjectsAndKeys: #"specialValue", #"specialKey", nil];
[notification setUserInfo:specialInformation];

How to take the text string from the push notifications?

I have an Iphone application in which i am recieving push notifications from the server.Now i am going to a view controller to show the message.Where that same message is loaded in a tableview .so thats not a problem.Now i am recieving two kinds of messages,one is a link and another is the message as earlier.if it is a link i want to open it in saffari,not need to go to tableview as usual.Can anybody help me to achieve this?
When You click on the push notification then you get a dictionary in the function - didReceiveRemoteNotification:
try this code:-
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
NSLog(#"remote notification: %#",[userInfo description]);
if (userInfo)
{
if ([[userInfo allKeys] containsObject:#"aps"])
{
if([[[userInfo objectForKey:#"aps"] allKeys] containsObject:#"alert"])
{
if([[[userInfo objectForKey:#"aps"] allKeys] containsObject:#"alert"])
{
NSString *urlString = [[userInfo objectForKey:#"aps"] objectForKey:#"alert"];
NSURL *url = [NSURL URLWithString:urlString];
if(url)
{
[[UIApplication sharedApplication]openURL:url]; // open in the safari...
}
else
{
// use the message in table view
}
}
}
}
}
}
The push notification is tied to your application, so in short its not possible to have a push notification from you application open safari directly. However, one workaround might go something like this:
user responds to notification (ie swipes to open it on the lock screen)
your app opens, and the data from the notification is passed into your applications
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions method. You could then interrogate the the data passed in as so
NSDictionary *dictionary = [launchOptions objectForKey:#"UIApplicationLaunchOptionsRemoteNotificationKey"];
// If dictionary is not nil, then your app is launched due to a push notification
if (dictionary != nil) {
NSDictionary *payload = [tmpDic objectForKey:#"aps"];
}
Once you've got your payload, look at the contents, and if it is a URL, call the safari URL scheme, passing in the URL. Like so
[[UIApplication sharedApplication] openURL:[NSURL URLWithString: <URL from payload>]];
This will help you achieve what you want to do, but it may mean the user briefly sees your app first before the os will switch them into safari.
A side note, why would you want to do this? Your users should not be launching a random URL from a notification, and I don't think Apple would like that too much. Prehaps they should be seeing some information about the URL first in your app, and then choosing whether they would like to open it in safari?

How to change application badge with push when application is closed

I'm trying to change the badge of the application I'm developing. When closed, unfortunately I was only notified a message without changing the badge.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[application registerForRemoteNotificationTypes:UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge];
NSDictionary* userInfo = [launchOptions valueForKey:#"UIApplicationLaunchOptionsRemoteNotificationKey"];
NSDictionary *apsInfo = [userInfo objectForKey:#"aps"];
NSInteger badge = [[apsInfo objectForKey:#"badge"] integerValue];
if( [apsInfo objectForKey:#"alert"] != NULL)
{
application.applicationIconBadgeNumber = badge;
}
But that does not change anything. I have not found any solution around. What method is invoked on arrival of a push notification and the application is closed? I also added:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
#if !TARGET_IPHONE_SIMULATOR
NSLog(#"remote notification: %#",[userInfo description]);
NSDictionary *apsInfo = [userInfo objectForKey:#"aps"];
NSString *alert = [apsInfo objectForKey:#"alert"];
NSLog(#"Received Push Alert: %#", alert);
NSString *badge = [apsInfo objectForKey:#"badge"];
NSLog(#"Received Push Badge: %#", badge);
application.applicationIconBadgeNumber = [[apsInfo objectForKey:#"badge"] integerValue];
#endif
}
But nothing...
Can you help me?
The badge icon number is governed by the badge property in the payload received as push message. The app itself has no role to play in what number shows up till the app becomes active. Setting the 'badge' property to any integer value (Note : it should not be string and should NOT be enclosed within "") does what is needed. The OS on receiving the notification looks for the value for 'badge' and immediately sets it on the app badge icon. All this happens when app is not active. To make sure it increments or decrements based on what happens in the app, the app should send message to server with the updated badge number.
In the active state, it is app's responsibility to handle the remote notification and change the badge icon.
Note : 'badge' property is enclosed in the 'aps' dictionary received within the payload. My payload looks like :
aps = {
alert = "Push notification!";
badge = 9;
sound = default;
}
You should define better what you want to do because it is not clear to me if wether you are talking about remote or local notifications, or what exactly you want to get and what are you getting.
Anyway, regarding remote notifications (APNS), take into account that you should set the badge as part of the payload if you want it to be set with the app closed. Your app does not get invoked unless the user manually opens the app (from the NotificationCenter or the dock).
On the other hand, when you are running the app, you will receive the call to
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
in your AppDelegate, and then you can set the badge by using
application.applicationIconBadgeNumber = badge;
Look at this, maybe it is a settings problem!:
application Icon Badge Number in ios5
Try also to give applicationIconBadgeNumber an int value, not NSInteger.
OK. Now my report about strange things.
I got it! It works good for now.
Problem was:
i created my App with push notification everything was ok with simple integer (1,8,99) but then i noticed that my integer 35.06 in the PHP variable $price did not recognize it at all even (int)$price unsuccessful . I thought the number is too long (but actually 4 digits is very popular). I decided to use
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
but as it was mentioned it does not work at all when the App is not started. No chance. It will never update the badge. I spent a lot of time thinking about what could be wrong and suddenly something came on my mind.
in the payload i just did this
'badge' => $price*100
an of course it worked good for me =)
I dont know what is the problem , why didn't work (int)$price (it is actually integer) but it is ok now.
My badge shows now something like this 3.506 and of course you can move the dot on step and you have your 35.06
Hope it could help you.

didReceiveRemoteNotification when in background

These kind of question has been asked a number of times but i have some specific situation going on.
When my application is active and I receive a PUSH message i'm successfully able to parse the custom payloads and such.
However when my application is in the background and the PUSH arrives the user has to click on the 'View/Open' button in order to get the didReceiveRemoteNotification called and the didFinishLaunchingWithOptions is called after that.
I need to have my application decide if they have to prompt the user with an UIAlert when in the background or suppress the push message based on some local settings.
Any help would be appreciated,
You app needs to handle all the possible push notification delivery states:
Your app was just launched
Your app was just brought from background to foreground
Your app was already running in the foreground
You do not get to choose at delivery time what presentation method is used to present the push notification, that is encoded in the notification itself (optional alert, badge number, sound). But since you presumably are in control of both the app and the payload of the push notification, you can specify in the payload whether or not there was an alert view and message already presented to the user. Only in the case of the app is already running in the foreground do you know that the user did not just launch your app through an alert or regularly from the home screen.
You can tell whether your app was just brought to the foreground or not in didReceiveRemoteNotification using this bit of code:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
if ( application.applicationState == UIApplicationStateActive )
// app was already in the foreground
else
// app was just brought from background to foreground
...
}
You have to do several things in order to manage the received push notification when the app is in background.
First, in your server side, you have to set {"aps":{"content-available" : 1... / $body['aps']['content-available'] =1; in the push notification payload.
Second, in your Xcode project, yo have to habilitate "remote notifications". It is made by going to the project's target -> capabilities, then enable the capabilities switch, and check the remote notifications checkbox.
Third, instead of using didReceiveRemoteNotification, you have to call application:didReceiveRemoteNotification:fetchCompletionHandler:, this will allow you to do the tasks that you want in the background, at the moment of receiving the notification:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
if(application.applicationState == UIApplicationStateInactive) {
NSLog(#"Inactive - the user has tapped in the notification when app was closed or in background");
//do some tasks
[self manageRemoteNotification:userInfo];
completionHandler(UIBackgroundFetchResultNewData);
}
else if (application.applicationState == UIApplicationStateBackground) {
NSLog(#"application Background - notification has arrived when app was in background");
NSString* contentAvailable = [NSString stringWithFormat:#"%#", [[userInfo valueForKey:#"aps"] valueForKey:#"content-available"]];
if([contentAvailable isEqualToString:#"1"]) {
// do tasks
[self manageRemoteNotification:userInfo];
NSLog(#"content-available is equal to 1");
completionHandler(UIBackgroundFetchResultNewData);
}
}
else {
NSLog(#"application Active - notication has arrived while app was opened");
//Show an in-app banner
//do tasks
[self manageRemoteNotification:userInfo];
completionHandler(UIBackgroundFetchResultNewData);
}
}
Finally, you have to add this notification type: UIRemoteNotificationTypeNewsstandContentAvailability to the notifications settings when you set it.
Apart from this, if your app was closed when the notification arrived, you have to manage this in didFinishLaunchingWithOptions , and just if the user taps on the push notification: The way of do it is:
if (launchOptions != nil)
{
NSDictionary *dictionary = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (dictionary != nil)
{
NSLog(#"Launched from push notification: %#", dictionary);
[self manageRemoteNotification:dictionary];
}
}
launchOptions is != nil when you launch the app by tapping on the push notification, if you access it by tapping on the icon, launchOptions will be == nil.
I hope it will be useful. Here it is explained by Apple.
Pass content-available = 1 with your payload, and will invoke didReceiveRemoteNotification even in background. e.g.
{
"alert" : "",
"badge" : "0",
"content-available" : "1",
"sound" : ""
}
One thing to keep in mind, when your push message arrives at the user's iPhone and they click "cancel", except for the icon badge number (they'll be taken care of by the OS), there would be no way for your in-the-background app to know about this push event and take any further actions.
Word of warning
I think your app logic is basing behavior on custom data in your push notification. This is not what push notifications are intended for. What you should alternatively do on didbecomeactive in your application is just ask your server for the data you need and was sending as payload anyway, and rely on that instead of your payload.
Because the documentation also states that as best practice. Because Apple does not guarantee your push notification from being received 100% of the times anyway.
Important: Delivery of notifications is a “best effort”, not
guaranteed. It is not intended to deliver data to your app, only to
notify the user that there is new data available.
However, if you want to have some indication of whether for instance the badge has been changed without relying on a user opening the app by clicking on the badge you could something like this:
A. you add a (correct) badge number to the payload of the push notification sent by your server. It for instance could look like this:
{
"aps" : {
"alert" : "You got your emails.",
"badge" : 9
}
}
B. you keep track of that badge number persistently in your app, for instance by storing it in NSUserDefaults.
Then in applicationDidBecomeActive can compare the applicationIconBadgeNumber property of UIApplication with your previously stored badge count and see if it has been increased or decreased and do some updates based on that.
- (void)applicationDidBecomeActive:(UIApplication *)application
{
NSNumber *badgecount = [[NSUserDefaults standardUserDefaults] objectForKey:#"badgecount"];
if (!badgecount) badgecount = #(0);
if ([UIApplication sharedApplication].applicationIconBadgeNumber != [badgecount integerValue]) {
//store the new badge count
badgecount = [NSNumber numberWithInteger:[UIApplication sharedApplication].applicationIconBadgeNumber];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:badgecount forKey:#"badgecount"];
[defaults synchronize];
// do some stuff here because it's different
}
}
As of recent iOS - I think 8 - if you've got remote notifications enabled as a background mode, one trick is to track whether you're entering the foreground as a flag.
#interface AppDelegate ()
#property (assign, atomic, getter=isEnteringForeground) BOOL enteringForeground;
#end
- (void) applicationWillEnterForeground: (UIApplication *) application
{
self.enteringForeground = YES;
}
- (void) applicationDidBecomeActive: (UIApplication *) application
{
self.enteringForeground = NO;
}
- (void) application: (UIApplication *) application didReceiveRemoteNotification: (NSDictionary *) userInfo fetchCompletionHandler: (void (^) (UIBackgroundFetchResult)) completionHandler
{
const BOOL launchedFromBackground = !(application.applicationState == UIApplicationStateActive);
const BOOL enteringForeground = self.enteringForeground;
if (launchedFromBackground && enteringForeground) {
// The user clicked a push while the app was in the BG
}
}