iOS Background Task/Push Notification - ios

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/

Related

Invoke iOS app at specific time and date

I want my iOS app to know when a specific date and time arrives without any failure. Now this time can be in days/weeks/months and my application can be in backgorund Or in terminated state.
So there are following options:
a. Local notification -- but it doesn't notify when my app is in background.
b. Silent Push notification -- it will work but it requires us to built server for same.
Is there any other option with which we can achieve same?
There is no way you can achieve this,
Your options are :
1) By using local notification like schedule notification on particular time and store that time and related activity in userdefaults. whenever app state changes to background to foreground in appdelegates - (void)applicationDidBecomeActive:(UIApplication *)application method write a code to handle desired functionality.
2) Silent push notification, which works only when your app is in background/minimized state. Once your app is Killed(swipe up from multitasking), even silent push notification cannot wake up your app.
3) To overcome the limitations of silent push notifications, Apple introduced Pushkit Notifications in iOS8, for voip apps like whatsapp, Skype, etc, in which push kit notification once received, wakes up your app even it is terminated or not running in background. Again you cannot use Pushkit unless you are actually using voip.
No. Sounds like you have to use push notifications.
This is the only thing that would work if your app is terminated.

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

push notifications and background fetch mode

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.

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.

Handling Remote Notifications

I was reading how handling remote notification on developer apple guide. My questions are two:
what is the interpretation of the phrase
The notification is delivered when the application isn’t running in
the foreground
isn’t running in the foreground covers background and not running or in the background state just. Based on the interpretation, the following sentence:
the application icon is tapped on a device running iOS, the application calls the same method, but furnishes no information about the notification.
has a different sense.
The second question concerns the situation where I get two consecutive remote notifications: When I open the app in the method
application:didFinishLaunchingWithOptions:
or
application:didReceiveRemoteNotification:
I have information on all notifications or just the last?
If your application is running, either in background suspended state or foreground, the method that will get called upon receiving a notification will always be application:didReceiveRemoteNotification:.
If your application is not running at all, upon launch after receiving a notification, it will trigger application:didFinishLaunchingWithOptions: and the options will be a non-nil object containing information about your remote notification.
As far as I know, only the last notification info is available.

Resources