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.
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.
When receive a push notification and my application is totally closed, how can handle this info?
Only can get data from NSDictionary on this method didFinishLaunchingWithOptions: or
didReceiveRemoteNotification:
for example: when the user open the application how get data from the push notification?, and not when the user open the push notification directly.
Is there a method that responds and detect if a notification has not been read?
You'll want to implement
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))handler
This will launch your app if needed, then you'll want to save the data somewhere so when the user next's starts the app you grab the data and do something with it.
From Apples Doc's:
Discussion
Use this method to process incoming remote notifications for your app.
Unlike the application:didReceiveRemoteNotification: method, which is
called only when your app is running in the foreground, the system
calls this method when your app is running in the foreground or
background. In addition, if you enabled the remote notifications
background mode, 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.
Just look into the method and I'm certain you'll figure it out :)
I did a quick google, these look like they will help:
SO example: didReceiveRemoteNotification: fetchCompletionHandler: open from icon vs push notification
The first tutorial i saw on it: http://hayageek.com/ios-background-fetch/
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
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 have an application, that uses Remote/Push notifications.
Background mode for remote notification is used, and everything works as expected.Application wakes up and takes all needed data from server.
But if Push notification alert is not cleared from Notification Center, and user click it application: didReceiveRemoteNotification: fetchCompletionHandler: method will be called again, and that means it will send new request to server, and that is undesirable behaviour.
First option is to check application state, but that causing me a problems, when application is in suspended.I have to do something like code below, but this doesn't work for me:
if([UIApplication sharedApplication].applicationState == UIApplicationStateActive || [UIApplication sharedApplication].applicationState == UIApplicationStateBackground){
}
if([UIApplication sharedApplication].applicationState == UIApplicationStateInactive){
}
Second option is, whether there is a way to clear alerts from Notification Center when user opens application, but I cannot find way to do it.
So is there a way to avoid second call of application:didReceiveRemoteNotification: fetchCompletionHandler: method?
You can send unique ID in your APNS message, then filter second call by remebering that ID - either in your app's temporary collection ( then you are called second time if you kill app between APNS message was received and is clicked ) or persistent storage ( to avoid second call in any case ).