iOS push notification: how to detect if the user tapped on notification when the app is in background?
Solution 1
OK I finally figured out.
In the target settings ➝ Capabilities tab ➝ Background Modes, if you check "Remote Notifications", application:didReceiveRemoteNotification:
will get triggered as soon as notification arrives (as long as the app is in the background), and in that case there is no way to tell whether the user will tap on the notification.
If you uncheck that box, application:didReceiveRemoteNotification:
will be triggered only when you tap on the notification.
It's a little strange that checking this box will change how one of the app delegate methods behaves. It would be nicer if that box is checked, Apple uses two different delegate methods for notification receive and notification tap. I think most of the developers always want to know if a notification is tapped on or not.
Hopefully this will be helpful for anyone else who run into this issue. Apple also didn't document it clearly here so it took me a while to figure out.
Solution 2
I've been looking for the same thing as you and actually found a solution that does not require remote notification to be ticked off.
To check whether user has tapped, or app is in background or is active, you just have to check the application state in
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
if(application.applicationState == UIApplicationStateActive) {
//app is currently active, can update badges count here
}else if(application.applicationState == UIApplicationStateBackground){
//app is in background, if content-available key of your notification is set to 1, poll to your backend to retrieve data and update your interface here
}else if(application.applicationState == UIApplicationStateInactive){
//app is transitioning from background to foreground (user taps notification), do what you need when user taps here
}
For more info check:
UIKit Framework Reference > UIApplication Class Reference > UIApplicationState
Solution 3
According to iOS / XCode: how to know that app has been launched with a click on notification or on springboard app icon? you have to check for the application state in didReceiveLocalNotification like this:
if ([UIApplication sharedApplication].applicationState == UIApplicationStateInactive)
{
// user has tapped notification
}
else
{
// user opened app from app icon
}
Although it does not make totally sense to me, it seems to work.
Solution 4
I ran into this problem, too — but on iOS 11 with the new UserNotifications
Framework.
Here for me it is like this:
- New Launch:
application:didFinishLaunchingWithOptions:
- Received from a terminate state:
application(_:didReceiveRemoteNotification:fetchCompletionHandler:)
- Received in Foreground:
userNotificationCenter(_:willPresent:withCompletionHandler:)
- Received in Background:
userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:
Solution 5
If somebody wants it in swift 3.0
switch application.applicationState {
case .active:
//app is currently active, can update badges count here
break
case .inactive:
//app is transitioning from background to foreground (user taps notification), do what you need when user taps here
break
case .background:
//app is in background, if content-available key of your notification is set to 1, poll to your backend to retrieve data and update your interface here
break
default:
break
}
for swift 4
switch UIApplication.shared.applicationState {
case .active:
//app is currently active, can update badges count here
break
case .inactive:
//app is transitioning from background to foreground (user taps notification), do what you need when user taps here
break
case .background:
//app is in background, if content-available key of your notification is set to 1, poll to your backend to retrieve data and update your interface here
break
default:
break
}
Bao Lei
Updated on July 11, 2022Comments
-
Bao Lei almost 2 years
There are a lot of stackoverflow threads regarding this topic, but I still didn't find a good solution.
If the app is not in the background, I can check
launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]
inapplication:didFinishLaunchingWithOptions:
call to see if it's opened from a notification.If the app is in the background, all the posts suggest to use
application:didReceiveRemoteNotification:
and check the application state. But as I experimented (and also as the name of this API suggests), this method gets called when the notification is received, instead of tapped.So the problem is, if the app is launched and then backgrounded, and you know a notification is received from
application:didReceiveNotification
(application:didFinishLaunchWithOptions:
won't trigger at this point), how do you know if user resumed the app from by tapping the notification or just tapping the app icon? Because if the user tapped the notification, the expectation is to open the page mentioned in that notification. Otherwise it shouldn't.I could use
handleActionWithIdentifier
for custom action notifications, but this only gets triggered when a custom action button is tapped, not when the user taps on the main body of the notification.Thanks.
EDIT:
after reading one answer below, I thought in this way I can clarify my question:
How can we differentiate these 2 scenarios:
(A) 1.app goes to background; 2.notification received; 3. user taps on the notification; 4. app enters foreground
(B) 1.app goes to background; 2.notification received; 3. user ignores the notification and taps on the app icon later; 4. app enters foreground
Since
application:didReceiveRemoteNotification:
is triggered in both cases at step 2.Or, should
application:didReceiveRemoteNotification:
be triggered in step 3 for (A) only, but I somehow configured my app wrong so I'm seeing it at step 2? -
Bao Lei over 8 years@bhusan have you read the details of my question? I'm seeing didReceiveRemoteNotification getting called when the notification just arrives (before the user taps on it). I wanted to find out whether the user tapped on it.
-
Gottfried over 8 yearsI have Background Modes set to "OFF" completely, but still get notified when a notification arrives with the app in background mode.
-
Peter Fennema over 8 yearsGreat! This helped me. It's a pity however that I need to switch off remote notifications. I would like to prefetch data when a push notification arrives AND detect the user tap. I can't find a way to achieve this.
-
Bao Lei over 8 yearsIt wouldn't work in this scenario. I tried that before. When that checkbox was checked (see my accepted answer for details), when the notification arrives, your line with comment "// user has tapped notification" will be entered, even though the user didn't tap the notification (the notification just arrived).
-
Werner Kratochwil over 8 yearsI disagree. I have "Remote notifications" checked in my background capabilities and it works the way described in my answer. I have "Background fetch" checked as well. Maybe that causes the change?
-
kalim sayyad over 8 yearsI set the Background mode to "ON" mode and enable the remote notifications. Still not able to detect the notification event.
-
Swapnil Dhotre over 8 yearsI have same problem Background mode is set to "ON" and enabled remote notification, but still not get notified when notification arrives to the app in background mode
-
Werner Kratochwil over 8 yearscould you please +1 my answer? ;-) I still need need some votes to participate more in stackoverflow. Thanks a lot
-
niks over 8 years@Bao - I think it will cause rejection on Appstore, as this option is basically used to download content related to notification in background. So if you are not downloading any content Apple may reject your app. developer.apple.com/library/ios/documentation/iPhone/Conceptual/…
-
Imran Sh about 8 yearsVery useful, Thank you body
-
Afshin about 8 yearsYupe, this is the solution. tnx.
-
Kevin Cooper about 8 yearsNote that this will be a false positive if the notification is sent while the user is on a different screen (for example, if they pull down the status bar and then receive a notification from your app).
-
Joe C almost 8 yearsYou didn't answer OP's question. He doesn't just want to know that there has been a notification. He wants to know if the user opened the App by tapping that remote notification.
-
Joe C almost 8 yearsThis works for me. I had been wondering why sometimes I'd get redundant notifications. It turns out that Werner is correct. If you open the App via the Alert display then you go thru didReceiveRemoteNotification another time, now while the App is UIApplicationStateInactive. Thx Werner.
-
Kostia Kim over 7 yearsWhat about app being UIApplicationStateInactive as a result of user engaging with Notification centre (swipe from top) or Control centre (swipe from bottom) while the app is on screen. Apparently, there is no way to tell whether APNS was received in Inactive state or user actually tapped it.
-
Dashrath over 7 yearsOn which trigger we should add this code , didReceiveRemoteNotification or didFinishLaunchingWithOptions?
-
Hamid Shahsavari over 7 yearsOn didReceiveRemoteNotification
-
mfaani almost 7 years@KostiaKim You're right, but that's a super edge case...other than that, this answer is the most valid in terms of separating between app in foreground...user tapping...app in background
-
Nickkk almost 7 yearsThanks, this kind of demystifies everything. Remember that in order for the delegate method to be called when the app is in the background, the push notification has to include the
content-available
key, but then the notification must be silent (i.e. not include a sound or badge) as stated in the official docs. -
Kiran Jadhav almost 7 years@Hamid sh,,,, I received push notification in all state i.e. when app is in forground, background, close(terminated)..! but my problem is that how to increment badge count when app is in background state and close (terminate) state???? Please tell me in details how i do it....? my app badge count is only increase when app is in forground state.....? if possible please tell me in brief.......!
-
Moxarth almost 7 yearsi have implemented everything perfectly and i am receiving notifications too . but it never goes inside application:didReceiveRemoteNotification: method unless user taps on notification message . do you have any solution regarding this ?
-
Moxarth almost 7 yearsi have implemented everything perfectly and i am receiving notifications too . but it never goes inside application:didReceiveRemoteNotification: method unless user taps on notification message . do you have any solution regarding this ?
-
DatForis over 6 years@KostiaKim I was actually able to fix the issue of not knowing whether the control center was open or if the user actually tapped the notification by adding a boolean that is set to true in the
func applicationDidEnterBackground(_ application: UIApplication)
and false in thefunc applicationDidBecomeActive(_ application: UIApplication)
this allowed me to show the in app notifications when the app is inactive due to the control center or the notifications list -
fabb over 6 yearsWith a minimum deployment target of iOS 10, this is no longer necessary, as the new
UserNotificationCenter
api does not suffer from these pesky problems anymore. -
Allan Nienhuis over 6 yearsit boggles my mind why Apple didn't present a different event or simply add a flag in the metadata to indicate that the user actually interacted with the notification. Having to 'deduce' whether the user took an action based on ambient information about the application state is pretty unreasonable for a key bit of information that affects the user's expectation of application behaviour. Perhaps the only thing to do is to create a custom action to open the app with that information?
-
sudo over 6 yearsI saw that Apple added this but couldn't figure out how to get the notification's custom payload this way.
-
sudo over 6 yearsThe problem is this delegate function also gets called if you receive a notification while in the app.
-
Ryan over 5 yearsThis is the official way which Apple says. According to the Apple's doc, it will be called whenever user interact with the push notification UI. If app is not in the background, it will launch the app in background mode and call this method.
-
dead_can_dance over 4 yearsNote in iOS10+ this approach is no longer necessary a UNUserNotificationCenterDelegate method can now be used instead which is called when a user interacts with a notification. You can also present stock notification alerts when your app is in the foreground as well. See stackoverflow.com/a/41783666/1761357 for detailed explanation.
-
dead_can_dance over 4 yearsThis is the correct answer for iOS 10+. Full explanation provided on another thread here: stackoverflow.com/a/41783666/1761357.
-
Nikhil Muskur over 4 yearsThis is function is called when the app is in a background state and becomes active and also when the app starts from the killed state
-
OhadM almost 4 yearsThis is the way to do it in iOS 11 +
-
Zorayr almost 4 years@NikhilMuskur only if "remote notifications" are enabled yeh?
-
Zorayr almost 4 yearsThis is just so complicated 🤦♂️
-
Claudiu about 3 yearsThis is working when interacting with a single notification at a time, what about the case where the user removes all notifications, is there a way to find out this?
-
Erkki Nokso-Koivisto almost 3 yearsduplicate to Yatin Arora / Aleks
-
Skywalker almost 3 years@ErkkiNokso-Koivisto I used their answer, but you really can't call it an exact duplicate. This is a much more detailed answer.
-
Skywalker almost 3 years@Claudiu I haven't tried that. Could you try to dismiss all and print the actionIdentifier? If its not calling the print, it means this method doesn't get called on this action. :(
-
Danilo about 2 yearsjust a note; use < 1000.0 for 1 sec why timeIntervalSince returns in ms
-
bauerMusic about 2 years@Danilo Are you sure? From what I know,
timeIntervalSince
returns in seconds. Documentation are unhelpful: " interval between the date object and ..." . Can you point me so a source? -
Muhammed Refaat almost 2 yearsThis answer helped me a lot, but just one question, what if I want to detect if I clicked the notification while the app is already open (as in that case the state will be 'active')