From my understanding, when app is running or in the foreground and a push notification is received, the app should NOT show any alert but the app delegate will call the didReceiveRemoteNotification delegate method and I should handle the push notification in that callback.
The push notification should ONLY display alerts/banners when the app is in the background.
However, our app gets push notification alert with an OK button when the app is running or in the foreground sometime, not all of the time. I'm wondering if it is something new in iOS 7 (I have never heard of this) or is it because I'm using UrbanAirship for push notification for our iOS app using alias of the user. The app will display the push alert when running and run the callback in didReceiveRemoteNotification.
Scratching my head over this. Does anyone know why?
When the App is in foreground, it should not display anything.
If you see alertView, it means you provided code for it.
Something along the following lines:
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
UIApplicationState state = [application applicationState];
if (state == UIApplicationStateActive) {
//app is in foreground
//the push is in your control
} else {
//app is in background:
//iOS is responsible for displaying push alerts, banner etc..
}
}
If you have implemented pushNotificationDelegate
[UAPush shared].pushNotificationDelegate = self;
then override, and leave it blank
- (void)displayNotificationAlert:(NSString *)alertMessage
{
//do nothing
}
You are most likely seeing the additional push notification because of the way Urban Airship is configured in your code. From Urban Airship's docs:
The sample UI includes an implementation of UAPushNotificationDelegate that handles alerts, sounds, and badges. However, if you wish to customize this behavior, you can provide your own implementation:
[UAPush shared].pushNotificationDelegate = customPushDelegate;
There is more information on the proper way to handle push notifications with Urban Airship in their support articles. Since you are using UA, I would recommend that you use their delegates etc. to handle incoming push notifications while in the foreground rather than implementing your own code in the didReceiveRemoteNotification app delegate method.
Hopefully that helps...if not, please post your code so that we can decipher what is going on. This would be very odd behavior indeed!
This answer is for swift users looking for the same thing
let state = application.applicationState
if (state == .active) {
//app is in foreground
//the push is in your control
} else {
//app is in background:
//iOS is responsible for displaying push alerts, banner etc..
}
Please refer to the checked answer if you guys have any more doubts.
Apple Documentation on handling Notifications
Related
I am trying to detect if my app was launched from push, and there are tons of threads and answers. They are all wrong in my case, and lead me to writing incorrect behavior. They all tell to write roughly this:
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
BOOL wasLaunchedFromPush = NO;
if (application.applicationState == UIApplicationStateInactive) {
wasLaunchedFromPush = YES;
}
...
}
Or this:
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
BOOL wasLaunchedFromPush = NO;
if (application.applicationState == UIApplicationStateInactive || application.applicationState == UIApplicationStateBackground) {
wasLaunchedFromPush = YES;
}
...
}
When I try this, my app thinks that it was started from a notification when I'm on a phone call, the app is in the background, pretty much always when the app is running but not directly active. When my users return to the app, app acts like they've tapped the notification and opened it, whereas the user hasn't interacted with it at all. I don't know why people accepted that as a correct answer in many questions.
How can I simply check if my app is launched from a notification or not, also regardless of the previous state of the app (running in the background or just launched)?
There is no simple way which is going to tell you that its open from pushNotificaiton specially when app is in active or in background. You have to do some work around,
UIApplicationStateInactive The app is running in the foreground but is
not receiving events. This might happen as a result of an interruption
or because the app is transitioning to or from the background
This is best candidate for the phone call interruption,
You can also add some other work around to check if app ever entered in background or not, if yes then after that if didReceiveRemoteNotification method get called its means its from push notification.
If you only want to know when your app was launched from a remote notification, you should check for this in - application:didFinishLaunchingWithOptions: or - application:willFinishLaunchingWithOptions:. You can check for the presence of UIApplicationLaunchOptionsRemoteNotificationKey in the launchOptions dictionary.
didReceiveRemoteNotification is call when your app is running and a remote notification is received. It is called regardless of any user interaction this is because if the app is running, there will not be a notification (pop up) for the user to interact with.
Checking against UIApplicationStateBackground is definitely wrong. If your push notifications are marked with content-available: 1 then your app is going to be called in that state so that you can perform your content download. This will happen without any user interaction.
The best I know of is using the check against UIApplicationStateInactive alone (i.e. your first code example).
As you say, this doesn't work if the notification arrives while your app has been interrupted by a phone call. That's an interesting problem. You could maybe keep track of call state using CTCallCenter but I've not done that and I don't know if you need VOIP permission to make it work.
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
NSLog(#"PUSH NOTIFICATION %#",userInfo);
if([userInfo[#"aps"][#"content-available"] intValue] == 1){
NSLog(#"SILENT PUSH NOTIFICATION");
//Here I'm inserting a flag value to my DB.
completionHandler(UIBackgroundFetchResultNewData);
}
else{
NSLog(#" GENERAL PUSH NOTIFICATION ");
completionHandler(UIBackgroundFetchResultNoData);
}
}
My silent notification payload is {
aps = {
"content-available" = 1;
sound = "";
};
}
To support I have added a key in info.plist in "Required background modes"
item 0 = App downloads content in response to push notifications
Also in capabilities section my Background Modes are ON with remote notification check mark is selected.
Now my question is when I run my app then I'm able to receive silent as well as general push notification and code is executing successfully in foreground mode but when I press home button (not forcefully quitting by swiping it away and also device's passcode lock is open) my app is going to background mode and then my code is not executing even I'm able to receive push notifications those are having alert and sound, but app is not launching in background mode.
I'm thinking that for foreground and for background mode whenever my app is receiving any push notification don't matter is it silent or general push notification my first log in the delegate method should have to print on the console i.e NSLog(#"PUSH NOTIFICATION %#",userInfo);
Please help I'm struggling with this since last 2-3 days.
My info.plist
I am doing almost exactly the same thing as you except I use the silent push notifications to present a local notification when the app is in the background and use it to update some state when the app is in the foreground. I am NOT registering for background fetch, only "remote-notification".
#Paulw11 is correct that you need to call the completionHandler each time didReceiveRemoteNotification is called.
I would check your plist to make sure your background modes are configured correctly. Maybe you could post the contents of your plist.
My notification payload looks exactly the same as yours so I don't think that is the problem. I initially had issues because the payload wasn't exactly right.
Keep in mind that if you kill the app (swipe it away), you will not get silent push notifications until the app is restarted.
I think you need to test once with 'content-available' outside 'aps', like the following:
aps = {
alert = "This is test alert";
badge = 1;
};
"content-available" = 1;
Looking on web and in many stackoverflow post i have seen that the only way to get remote push notification when the app is in background (and it is launched from icon and not from push message) is to call the server when the app is loaded and get the "last" messages.
I've made this test with instant messaging app (i dont tell the name of the app, but i think you understand):
From another device i've sent one message to my device
When my device has received the notification i have wait for push notification pop-up to disappear.
At this point i have take device offline (no internet connection)
I have then open the application and in the list the message was correctly added
So, if i'm in foreground, i can handle the notification on method didReceiveRemoteNotification.
If the app is in background i can handle the nofification in didFinishLaunchingWithOptions (if i launch it with push notification pop-up).
How it's possible to handle the notification when the application is in background and it is launched from icon and not from the push pop-Up?
Thanks
(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
UIApplicationState state = [application applicationState];
if (state == UIApplicationStateActive)
{
// write code here for handle push notification when app is in foreground
}
else
{
// write code here for handle push notification when app is in background
}
}
I am building an app that has a feature of requiring logins whenever the user goes in and out of the app (seems like overkill, but it is necessary). I am doing this in the applicationDidBecomeActive: method of the AppDelegate, which pops up a login modal view whenever the method is called. The app also creates push notifications, and I recently noticed that whenever the user enters the app via a push notification, they can bypass the whole login process. Not exactly sure if this is some bug in the app or because app entry through push notifications is not calling the applicationDidBecomeActive:.
How do push notifications interact with an app when they are selected?
When an user enter through a push notification, a special method gets called, implement that method to detect if they came from the background:
- (void)application:(UIApplication *)application didReceiveRemoteNotification: (NSDictionary *)userInfo
{
if ( application.applicationState == UIApplicationStateInactive || application.applicationState == UIApplicationStateBackground )
{
//came from background, show the login screen
}
}
Instead of applicationDidBecomeActive, use applicationDidEnterBackground.
And then, the password requiere is set when the app minimizes, and not when it comes up again.
I have the following issue: "My app receive some remote notifications from an own server just to show to the user some practical information. I am not using a icon badge, because I don't need it. If the application user touch the remote notification from the iOS Notification Center my application can catch it without any problem, I receive the options from application:didFinishLaunchingWithOptions: or, if the application is open I catch the remote notification with application:didReceiveRemoteNotification: selector. But, now I want to remove these notifications from iOS Notification Center because It is just a message and I have been looking for the answer in another posts and I've tried these solutions in my app and they don't work"
Some solutions were the next:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
[application cancelAllLocalNotifications];
application.applicationIconBadgeNumber = 0;
...
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
...
if (launchOptions) {
[application cancelAllLocalNotifications];
application.applicationIconBadgeNumber = 0;
}
...
}
And the remote notification still in the iOS Notification Center, how can I remove from that place without any tricky code or is an iOS SDK issue? I don't think that an issue was possible because Tweetbot app remove its remote notifications from iOS Notification Center after you enter to the app.
Regards!
With introduction of UNUserNotificationCenter for iOS 10 and above, it is now possible to remove few or all remote notifications of your app.
UNUserNotificationCenter documentation
With a shared singleton instance of this class, it is possible to manage delivered remote notifications on the device. Specifically, the following methods can be used:
func removeDeliveredNotifications(withIdentifiers: [String]) if you want to remove specific notification of your app, OR func removeAllDeliveredNotifications() to remove all notifications of your app.
First of all make sure you haven't set badge notification to be off in the control panel (I noticed that if the badge has a number to begin with, then badging is turned off in the control panel, it cannot be set to 0).
If its not turned off then in addition to setting applicationIconBadgeNumber to 0, also try canceling all local notifications (even if you haven't queued any, if you have first get a list of them, then cancel them, then register them back again). Yes clearing local notifications can have an effect on being able to clear the badge number for remote notifications.