push notifications and background fetch mode - ios

It's my understanding that the system will either wake you from being closed or running in the background, and allow you to fetch BEFORE it displays the system alert to the user.
I have to download some data to show the user when they tap a push notification.
I am seeing my fetch activities being performed WHILE the push is shown to the user. It is allowing user to tap the notification and launch the app before we've completed the data fetch.
Is this correct?

I didn't have the chance to use push notifications and background fetch mode myself,
but according to the docs:
the system sends the notification to your app (launching it if needed)
and gives it a few moments to process the notification before displaying
anything to the user. You can use those few moments
to download content related to the push notification and
be ready to display it to the user.
so as i understand you are suppose to have some time to react (download data) to a notification before presenting something to the user and not while the notification is shown
the docs don't mention what is considered "few moments" (not that i have seen).
so maybe the download operation is taking more than those "few moments"
hope this helps

Using so-called "silent" push notification in iOS7 you can send specific silent push from your server. You need to add additional key content-available in your aps dictionary
"aps" : {
"alert" : "alert",
"sound" : "sound",
"badge" : badge,
"content-available" : 1
}
Then you need to set two background modes in your project: Remote notifications and Background fetch.
Now every remote push will call for
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
and you can implement any background logic here. For example you can start some fetch process (no longer then 30 seconds!), show custom local notification (which substitutes for standard remote on-screen push) at the moment or on fetch completion.
Be sure that push notifications are allowed for your app in Notification center and that you allow Background App Refresh for your app in Settings/General.
Another important thing is that silent pushes work until you unload you app from background manually (double tap on home button).
Note that this silent mechanism worked incorrectly until iOS7.1

You are in control to choose if to show the AlertView even if using third party like UrbanAirShip.
Any how, you can decide not to show it, initiate background fetch with completion block.
After that you can use local notification to show what ever data you need to show.
Behaviour is little different in iOS 7 and below it.
If you can provide some more code/implementation I might be able to help a bit more.

Related

iOS Background Task/Push Notification

I am building an app that needs to speak data while the app is in the background (or screen is off). The speaking part is done via AVSpeechSynthesizer.
My Android app launches a service that listens for the data and whenever it needs to say something, I say it and its done. Now iOS doesn't allow these kind background tasks from what I read. The closet thing is called 'Executing Finite-Length Tasks' which looks like has a time limit of 10 mins max. So this will not work for me. Instead it looks like I need to use Push Notifications.
Looking at the documentation for Push Notifications, if I understand it correctly, if my app is in the Foreground, then my app receives the Push Notification instantly. While if my app is in the Background, a notification is set (notification center), and once the user hits the notification, my app launches with the payload.
The question here is, is there anyway to make a push notification wake my app immediately so I can speak some info?
Or what are some of the other alternative approaches that should be used in this case?
My other idea would be to implement some sort of mp3 stream per user, that would stream audio which I could play in the background. But this seems excessive for what I am trying to accomplish?
I'm not sure if you'll be able to invoke speech synthesis from the background, but you can have you app notified when the push arrives. The trick is to implement the
- (void) application: (RMApp *) application didReceiveRemoteNotification: (NSDictionary *) userInfo fetchCompletionHandler: (void (^)(UIBackgroundFetchResult result)) completionHandler
UIApplicationDelegate method (note the completionHandler parameter).
You must also set the Remote Notifications Background Mode capability.
And you must set content-available in your push notification payload.
A decent writeup on these steps found here:
http://samwize.com/2015/08/07/how-to-handle-remote-notification-with-background-mode-enabled/

Prevent auto generated push notification

When we receive a push notification while the application is in the background mode, it automatically uses aps and other parameters like Sound, Badge, Alert to generate a notification that appears on top.
What I want is to prevent that auto generated notification let it call didReceiveRemoteNotification and generate my custom local notification and display it on top and notification centre.
The reason behind this is that the message is customised according to situation which is managed locally after some data received in push notification.
I haven't tried anything, because I couldn't find any solution for this kind of scenario. I don't even know whether it is even possible or not.
Any help or other suggestion that could to solve this other way is highly appreciated.
You can have a look to iOS Silent Notifications here
But you have 2 differences cases :
1 your app is in front, the did receive remote is called, and the notification is not displayed.
2 your app is in background, and I don't think the didreceiveRemove is called.
So in the 2 situations, you will not achieve your goal. You shroud maybe try to customize the notification before sending it
Even when your App is in the background, suspended, inactive or terminated it is woken by a Silent push notification.
(Note: the only scenario when the app is not woken by silent push is when it had been killed off by the user from the control centre)
So you can send a silent push, perform whatever operations you need to perform on the data and then generate a local notification which would go in the tray.

iOS: Making push to run a method without displaying a notification

Is it possible to in iOS to get a push from the server and then to run a method without displaying a notification at all? For example, to check if now is the configured time and if it is to dispaly a notification and if not to send the server a non availble message.
Yes, what you are looking for are silent push notifications which got introduced in iOS 7. Take a look at the docs regarding push notifications which state:
The aps dictionary can also contain the content-available property. The content-available property with a value of 1 lets the remote notification act as a “silent” notification. When a silent notification arrives, iOS wakes up your app in the background so that you can get new data from your server or do background information processing. Users aren’t told about the new or changed information that results from a silent notification, but they can find out about it the next time they open your app.
and
content-available -
number -
Provide this key with a value of 1 to indicate that new content is available. Including this key and value means that when your app is launched in the background or resumed, application:didReceiveRemoteNotification:fetchCompletionHandler: is called.
(Newsstand apps are guaranteed to be able to receive at least one push with this key per 24-hour window.)
You can then react accordingly and eventually actually trigger another notification if you feel like the user needs to be informed about something (not 100% sure about that one though).
A little more in-depth information and code can be found in this objc.io post.
Yes, it is possible:
Implement didReceiveRemoteNotification:fetchCompletionHandler:
Make sure to register for remote notifications, see documentation here:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)];
return YES;
}
Also make sure to edit Info.plist and check the "Enable Background Modes" and "Remote notifications" check boxes:
Additionally, you need to add "content-available":1 to your push notification payload, otherwise the app won't be woken if it's in the background (see documentation here):
For a push notification to trigger a download operation, the
notification’s payload must include the content-available key with its
value set to 1. When that key is present, the system wakes the app in
the background (or launches it into the background) and calls the app
delegate’s
application:didReceiveRemoteNotification:fetchCompletionHandler:
method. Your implementation of that method should download the
relevant content and integrate it into your app
So payload should at least look like this:
{
"aps" = {
"content-available" : 1,
"sound" : ""
}
}
Just leave the sound property empty and omit the alert/text property and your notification will be silent.
Unfortunately, the app won't be woken up, if it's not running at all (force-quit), see this answer.

iOS retrieve remote notification payload

I have implemented the UIApplicationDelegate method -(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler to handle push notifications, it works fine. In some situations, I need to retrieve the payload of the push notification. But sometimes this delegation method is not called.
I have a question about retrieving the payload (userInfo) in this scenario:
The app running either in background or not launched. The app received a push notification, a banner is shown, sound is played, and message is displayed, app icon badge increased, and the push notification can be seen in the iOS notification centers. If the user taps the notification when it's shown or in the notification center, the app launches, and the didReceiveRemoteNotification: method is called.
However, if the user just tap the app icon and launch the app in normal ways, the method is not called, and I can't retrieve the userInfo.
From Apple's documentation on handling push notifications:
The notification is delivered when the app isn’t running in the foreground. In this case, the system presents the notification, displaying an alert, badging an icon, perhaps playing a sound, and perhaps displaying one or more action buttons for the user to tap.
The user taps a custom action button in an iOS 8 notification. In this case, iOS calls either application:handleActionWithIdentifier:forRemoteNotification:completionHandler: or application:handleActionWithIdentifier:forLocalNotification:completionHandler:. In both methods, you get the identifier of the action so that you can determine which button the user tapped. You also get either the remote or local notification object, so that you can retrieve any information you need to handle the action.
The user taps the default button in the alert or taps (or clicks) the app icon. If the default action button is tapped (on a device running iOS), the system launches the app and the app calls its delegate’s application:didFinishLaunchingWithOptions: method, passing in the notification payload (for remote notifications) or the local-notification object (for local notifications). Although application:didFinishLaunchingWithOptions: isn’t the best place to handle the notification, getting the payload at this point gives you the opportunity to start the update process before your handler method is called.
If the notification is remote, the system also calls application:didReceiveRemoteNotification:fetchCompletionHandler:.
If the app icon is clicked on a computer running OS X, the app calls the delegate’s applicationDidFinishLaunching: method in which the delegate can obtain the remote-notification payload. If the app icon is tapped on a device running iOS, the app calls the same method, but furnishes no information about the notification.
The highlighted part kinda saying there is no obvious way to access the payload of the push notification in this way. So is there a way to work around this issue?
Thank you!
It is the default behavior of iOS. You will never know the payload unless user opens your app via tapping on the notification.
You can use silent push notifications if you want to send custom data (max 2048 bytes) or commands to your mobile app.
In the push notification set 'content-available' to 1 so you app gets some time to process data and also add your custom content to the notification.
I also use silent push notifications to trigger my apps to update by REST HTTP calls, since my data can be bigger than the max size... The only downside is that Apple might block your background activities if you are battery or processor intensive. Visual push notifications are always delivered.
Things I hate most are visual push notifications like 'you've got a new message' , on which I click sometimes when no data connection is available and the app will not show me the message... You can solve this by sending a silent push notification with data and only if the data could be fetched from the server, or
stored correctly in case you can send it all in the notification, you set a local notification.
Choose between visual and silent push notifications wisely is my only advise.
Check the following link for more official Apple info: https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html

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