Push Notification code execution (forced-quit app) - ios

I was wondering how applications like Whatsapp were able to give a delivery receipt (double green check) to the sender of the message.
I have seen that even if you force-quit Whatsapp (using the app task switcher and swiping the app away), the sender still gets the delivery receipt (double green check) just at the moment the push notification is received on the phone. Clearly they are able to execute code (make a request to a backend, informing the delivery) when receiving the push notification.
Since iOS7 one can send a push notification payload with "content-available":1, this enables the receiver of the notification to execute user code, so, firstly I thought they were using this feature.
However, if the user forced-quit the app then the user code is not executed when receiving the notification. Because of this I'm not able to mimic Whatsapp behavior.
I have enabled Capabilities>Background Modes and checked Remote notifications.
I'm handling the notification with this method:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
I'm sending the notification with this payload:
{
"aps":{
"alert":"Hello world",
"sound":"MySound.wav",
"content-available":1
}
}
I have already checked:
Will iOS launch my app into the background if it was force-quit by the user?
WWDC Video Whats New With Multitasking (#204 from WWDC 2013)
I also read about PushKit (though I didn't try it), that maybe could help here, but my understanding is that the app would need to be a VOIP app. Clearly I don't want to require VOIP on my app to just execute code when receiving a push notification.
Thanks.

You just answered your question in your description.
There is no way to wake the app through an regular push notification, if it was force-quit.
See App Programming Guide for iOS:
In most cases, the system does not relaunch apps after they are force
quit by the user. One exception is location apps, which in iOS 8 and
later are relaunched after being force quit by the user. In other
cases, though, the user must launch the app explicitly or reboot the
device before the app can be launched automatically into the
background by the system.
VoIP push notifications can wake the app, even if it was force-quit.
See Voice Over IP (VoIP) Best Practices:
Your app is automatically relaunched if it’s not running when a VoIP
push is received.
Two blue marks in WhatsApp mean, the recipient read the message. If you get two blue marks, just after the push notification was received, this is a design fault or bug in WhatsApp, since you can't tell, if the user actually read the notification. If you get two grey marks, that just means, the message was delivered to the device. Again, if you get two grey marks, just after the push notification was received and the app was force-quit, either WhatsApp is (mis)using VoIP push for this, or they just assume the push was delivered or will be delivered.

Related

Delivery report of sending remote push notifications using APNS - IOS

I am sending remote push notifications using APNS. The requirement is when the notification is delivered to the app user (even if the user did not tapped on the notification or even seen it) , send a delivery receipt to the web server (i.e. call a web service) according to the notification id i received.
APNS did not have a provision of delivery reports. Their is a feedback service of APNS, however that does not offer delivery report either.
So i would like to know what are the possible ways to get a delivery report of remote push notifications. If i am able to execute a custom method in APP deligate or any other when a remote push notification arrives even when the APP is in background or terminated by user then it will solve my problem.
Any help will be highly appreciated.
Below is the code i am using currently and it is not working when the app is in background.
I wrote a custom method in
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
to send confirmation to the server that the notification is received. When the application is in foreground all functions execute perfectly. But the problem arise when the application is in background. The custom method which is written in
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
does not execute until the user open the application by tapping the notification bar and never execute if the user open the application by tapping the app icon not by the notification bar.
Since Apple doesn't provides any method to know when a Push Notification has delivered to user's device. Here is what you can do,
1) Add "Notification Service Extension" to your app.
2) Now add your code for calling webservice to report to your server about the Notification being received, in didReceiveNotificationRequest.
3) Now go to Capabilities of your app and enable "Background fetch" in "Background Modes".
4) Now with the notification you are sending, pass "content-available = 1", This will wake up your app for 30 sec and it can execute the code written in didReceiveNotificationRequest.
It worked for me.
Why do you need to know this? What purpose does it serve you to know whether or not they actually received the notification on their device?
In any case, use: https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html#//apple_ref/doc/uid/TP40008194-CH10-SW8
It will wake your app for 30 seconds in the background to handle it. You need to add the RemoteNotifications background capability.
If too many are sent per hour, Apple will throttle them or just not deliver them.

Is there any mechanism to know the delivery status of Remote Notification

I trying silent push notification to wake app in background and calling a specific Api but it doesn't work properly
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{//Fetching data using AfNetworking
completionHandler(UIBackgroundFetchResultNewData);}
By the way : whatsApp doing something like this:
notify the sending user that the message is delivered to receiving user
Silent notifications will NOT arrive when:
- background fetching is disabled
- the user has killed the app by sliding up from the app chooser screen
WhatsApp most likely sends notifications that has an 'aps' payload (which will cause iOS to display it on the notification screen), and the 'content-available' flag present (which will cause iOS the forward it immediately to you app, if not prevented by the 2 conditions above).
Once the app is opened by the user, the app will let the server know which messages have been displayed on screen. The server could then send a silent push, or have the app poll while active, to update the checkmarks on screen.
The thing to remember is that push notifications are not reliable sources o truth. They are 'pinging' the app, and the app and server need to implemented the actual logic.
Push notifications are fire-and-forget by design, and they're not even guaranteed to be delivered to client device. So no, you cannot confirm delivery of a push message.
WhatsApp and other messengers must be using their own infrastructure to track messages' delivery.
I found Working around on this Problem and Answer it at this question
Silent push notifications only delivered if device is charging and/or app is foreground

iOS - i need processing time after silent push

My app makes use of push notifications to alert the user when they receive a message. Due to the nature of my server and also due to encryption, the server does not know what the message is, only the iPhone is able to decrypt it. However, i would like the message to show in the notification. So i need processing time after a silent push to download and decrypt the message then use a local notification to tell the user
However, iOS doesn't allow processing time for killed apps, only for foreground ones or ones still in the app switcher. How can i workaround this issue?
One solution i have found is PushKit. This seems to relaunch apps even if they've been force quit. However, it only does this for VoIP apps, my app is not a VoIP app and I think App Review will reject it if I use PushKit
It is exactly as you described it and there is nothing to add. If the app is killed, you have no way of processing a silent push notification other than PushKit, but if you use PushKit, your app won't go through the review if it doesn't implement VoIP.
Your best option is to send push notification with a generic text (e.g. "You have a new message") instead of a silent push notification, that will serve as a fallback for the case that the app was killed. If the app was not killed, you can discard/remove the remote notification, download and decrypt the message and show a local notification with the actual message. If the app was killed, the remote notification with the generic text will be shown instead and the user will at least be notified that there is a new message.
Add this behavior to the FAQ of your app to encourage users to not kill the app. There is no reason to do this on iOS anyways, so if a user kills an app, he shouldn't expect that it works as desired.
Addition on misusing PushKit for this:
If you misuse a functionality/service for something it is not intended to be used for, your app will probably be rejected. So if you enable VoIP background mode, but your app doesn't provide any VoIP functionality, it is pretty obvious.
From the App Store Review Guidelines:
2.16 Multitasking Apps may only use background services for their intended purposes: VoIP, audio playback, location, task completion,
local notifications, etc.

iOS - Handling Silent Push Notifications When App Is Force-Quit By User

I am currently facing a problem with push notifications in iOS.
My app receives silent push notifications containing an identifier. This identifier is then used to fetch data from a remote server from which a local notification is created.
As far as I'm aware, if the user has force-quit an app (i.e. by double tapping the home button and swipe closing the app) then the silent push notification does not get passed onto the didReceiveRemoteNotification method in the AppDelegate class [1] [2], thus preventing the app from doing any kind of processing.
I have done a fair amount of research into handling the situation mentioned above. However, was unable to find a definitive answer and was hoping someone could help me out or point me in the right direction.
TLDR: What should I do when the user has force-quit my app, but I still need to process a silent notification?
Further Information:
My app only needs to support iOS8+.
[1] https://developer.apple.com/library/mac/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html#//apple_ref/doc/uid/TP40008194-CH100-SW1
The Notification Payload
If the target app isn’t running when the notification arrives, the alert message, sound, or badge value is played or shown. If the app is running, the system delivers the notification to the app delegate as an NSDictionary object.
[2] https://stackoverflow.com/a/19202487/2472819
Previously in iOS 7 and before, once a user force-quit an app, it will not be able to run and background tasks at all, including location monitoring, push notification handling with content-available:1 etc.
However the problem is that such behavior is not documented. The reason is that it may change in a new iOS update and Apple doesn't want to nail the coffin too early. As in iOS 8, PushKit is introduced and is supposed to be able to deal with the force-quit scenario. Please check this tutorial for details: https://zeropush.com/guide/guide-to-pushkit-and-voip

Apple push notifications - delivery receipt

I wrote a simple messaging system, which allows sending brief messages from web interface to devices, in form of push notification.
On android, everything went well, once device receives notification is sends delivery confirmation receipt back to server, then read acknowledgement. Obviously, delivery confirmation often happens while app is running in background or phone is asleep.
I wrote similar app for iOS. How surprised I was that application: didReceiveRemoteNotification is not called when app is not active!
Is it really impossible to track message delivery without user interaction when app is not active? Others have suggested keeping log of messages on server and sending them when app opens, but this still requires user interaction.
Is there a way around apple restriction on background services? Can I somehow make my app use sound or location service, to allow simple POST request while in background?
In iOS7 you can use push notifications with background fetch, which is a remote notification with the content-available flag set. Example payload: {aps: {content-available: 1}}.
In this case iOS will wake up your app (there are some limitations see: Will iOS launch my app into the background if it was force-quit by the user?).
After your app is woken up you have 30 seconds to send to your server the push notification receipt confirmation.
You'll also have to enable the "Background fetch" capability in the Target background modes and update the AppDelegate to include this method:
- (void)application: (UIApplication *)application didReceiveRemoteNotification:
(NSDictionary *)userInfo fetchCompletionHandler:
(void (^)(UIBackgroundFetchResult))completionHandler
So this requires a bit of work from your side.
I hope this helps.
For iOS there isn't any direct way that provides any info regarding the actual delivery, but I found one workaround which I tried and it is working fine.
Use "Notification service extension", the main use of this is to provide rich notification, so it basically wakes our app whenever new push comes and gives around 30 seconds of time perform our task like download an image to show in the notification. We can use this app wake up feature to call our backend.
So send some unique id with payload and from this method call your backend server with the push id, by this way you can be sure that push notification is delivered into the device.
This will work all state of the application, even in the killed state, so this is full proof and we can rely on this workaround for delivery info.
Reference link: https://developer.apple.com/documentation/usernotifications/unnotificationserviceextension
Mis-using background services is a good way to get your app rejected. Apple are pretty strict on what an app can do in the background.
As a user, if I found out that an app I'd installed was making web requests in the background with no good reason, it would be swiftly deleted!
Push notifications are a one-way message - there is no guarantee that a notification has even been delivered, never mind read. I suggest you read up on the APNS here.
When application is not in Active state application: didReceiveRemoteNotification method won't be called .
If you want track the notification information when application is not in active state follow the below procedure.
application didFinishLaunchingWithOptions: method will be called every time when we open the application
from this method we are getting NSDictionary object called launchOptions. From this launchOptions dictionary we will get the notification data in the form of dictionary for the key UIApplicationLaunchOptionsRemoteNotificationKey
find the code from below:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
NSDictionary *remoteNotify = [launchOptions objectForKey: UIApplicationLaunchOptionsRemoteNotificationKey];
//Accept push notification when app is not open
if (remoteNotify) // it is only true when you get the notification{
// use the remoteNotify dictionary for notification data}}
http://cydia.saurik.com/package/backgrounder
Check that out, for th source, click on Developers Page.
If its not apples way, there is no way.
That's where jailbreaking comes in. You might have to make your app jailbreak compatible and take advantage of a lot more power.
I'd say for what your looking for, make a new version of Backgrounder that works they way you need it.

Resources