Implementing Long-Running Background Tasks in iOS - ios

my client asks me to develop some app that periodically retrieves the user location & the phone battery status, and then send them to our backend server for data analysis, then feed back by push notification.
But through the app doc, I get to know that from apple ios dev doc:
For tasks that require more execution time to implement, you must
request specific permissions to run them in the background without
their being suspended. In iOS, only specific app types are allowed to
run in the background:
Apps that play audible content to the user while in the background,
such as a music player app
Apps that keep users informed of their
location at all times, such as a navigation app
Apps that support
Voice over Internet Protocol (VoIP)
Newsstand apps that need to
download and process new content
Apps that receive regular updates
from external accessories
I'm wonder if this would be feasible if we wrap this app as some navigation app so we can have long-running background tasks? Does appstore will reject on our app?
BTW, what is the definition of navigation app by Apple?

You might consider using:
[CLLocationManager startMonitoringSignificantLocationChanges];
This will cause your app to be restarted if it has been killed whenever the location changes significantly, allowing you to update the details on the server at fairly regular intervals, assuming the user is moving. This does not require any special background permission. From the docs:
If you start this service and your application is subsequently terminated, the system automatically relaunches the application into the background if a new event arrives. In such a case, the options dictionary passed to the locationManager:didUpdateLocations: method of your application delegate contains the key UIApplicationLaunchOptionsLocationKey to indicate that your application was launched because of a location event.
Your other option is to configure the app as requiring continuous location updates in the background, but without knowing the primary function of the app it is hard to know if this will pass store submission or not.

https://github.com/yarodevuci/backgroundTask Check my code here I am using audio player that plays blank wav file Works perfectly on IOS 8 Battery usage around 10% in 24 hour period How to use:
var backgroundTask = BackgroundTask()
backgroundTask.startBackgroundTask() //Starts playing blank audio file. You can run NSTimer() or whatever you need and it will continue executing in the background.
backgroundTask.stopBackgroundTask() //Stops the task

Related

CoreBluetooth background execution 10sec?

Because the apple doc is quite vague concerning this point :
Upon being woken up, an app has around 10 seconds to complete a task
Does this mean that after 10 sec the app will go back to its "suspended" state ? Theoretically, is it possible to "force" the app to stay awake after these 10 sec ? (private app).
In my case the device would be connected to a car.
Does this mean that after 10 sec the app will go back to its
"suspended" state ?
If you read carefully :
Upon being woken up, the app has around 10 seconds to process the
data. Ideally, it should process the data as fast as possible and
allow itself to be suspended again. However, if more time is needed,
the app can use the beginBackgroundTaskWithExpirationHandler: method
to request additional time; it should do so only when absolutely
necessary, though.
Apps generally awake by Background modes(like location service, audio, push notification and so on) and for some modes like location service it will stay awake until the location data is being captured and for some, it doesn't stay awake for much time like push notification. So it depends on the task that is being performed. For Bluetooth, if it's connected with another Bluetooth device then it will stay awake.
Theoretically, is it possible to "force" the app to stay awake after
these 10 sec ? (private app).
Yes, it's possible.
Each of the preceding modes lets the system know that your app should
be woken up or launched at appropriate times to respond to relevant
events. For example, an app that begins playing music and then moves
to the background still needs execution time to fill the audio output
buffers. Enabling the Audio mode tells the system frameworks that they
should continue to make the necessary callbacks to the app at
appropriate intervals. If the app does not select this mode, any audio
being played or recorded by the app stops when the app moves to the
background.
Note : If you need it for your private app then you can check this here. Your app will be rejected if you add the solution and apply for appstore.
In XCode, go to your project->Capabilities->Background Modes and mark the Background Modes to On. Mark also Uses Bluetooth LE accessories:
Apps that work with Bluetooth peripherals can ask to be woken up if
the peripheral delivers an update when the app is suspended. This
support is important for Bluetooth-LE accessories that deliver data at
regular intervals, such as a Bluetooth heart rate belt. You enable
support for using bluetooth accessories from the Background modes
section of the Capabilities tab in your Xcode project. (You can also
enable this support by including the UIBackgroundModes key with the
bluetooth-central value in your app’s Info.plist file.) When you
enable this mode, the Core Bluetooth framework keeps open any active
sessions for the corresponding peripheral. In addition, new data
arriving from the peripheral causes the system to wake up the app so
that it can process the data. The system also wakes up the app to
process accessory connection and disconnection notifications.
For more detail you can refer Apple documentation.
Try this:
[[UIApplication sharedApplication] setIdleTimerDisabled:YES];

iOS background execution for health care apps

I need to implement the following requirement:
iOS app should periodically(Ex:- Every 1 hour) collect the data from health app and send the data to the server when in background mode.
I tried implementing this scenario like below :
I implemented the following code:-
func applicationDidEnterBackground(application: UIApplication) {
self.bgTask = application.beginBackgroundTaskWithName("updateMedicalData") {
self.endBackgroundUpdateTask()
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)) {
print("Time remaining ::",application.backgroundTimeRemaining)
NSTimer.scheduledTimerWithTimeInterval(25, target:self, selector:#selector(self.performBackgroundTask), userInfo:nil, repeats:true)
}
}
I have implemented the logic of fetching the data from health app and sending server in the method "performBackgroundTask()"
But the issue is, App is running in the background only for 3 min and expiration handler is called.
I have set the key "Required background modes" to "App downloads content from the network" and for the key "Application does not run in background" to "NO" in plist file.
Can anyone tell me if it is possible to implement the above requirement ?
It is only possible for certain types of Apps to have longer background execution. More specific:
For tasks that require more execution time to implement, you must request specific permissions to run them in the background without their being suspended. In iOS, only specific app types are allowed to run in the background:
Apps that play audible content to the user while in the background, such as a music player app
Apps that record audio content while in the background
Apps that keep users informed of their location at all times, such as a navigation app
Apps that support Voice over Internet Protocol (VoIP)
Apps that need to download and process new content regularly
Apps that receive regular updates from external accessories
https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
Please look at this link to see whether this will works for you. I guess that the "Background fetch" might suit your needs. In that case, you need to set your UIBackgroundModes value to "fetch". Did you already do this?
Good luck!
Adding to what Robski18 has answered. There's no way you can periodically send data to the server. The only way to do this is for the server to periodically send your app a silent push notification and have the background mode which is called in that answer "Apps that need to download and process new content regularly". Except you will be pushing content not fetching it.
Even if the server sends the push periodically that does not mean the app will receive them periodically, if the server sends them every hour the app might not receive one for several hours and then they'd be all bunched together.
Also if the user kills the app then the app will not receive the pushes.
Perhaps the BGTaskScheduler is what can do the job. Though if your device is bluetooth based, there is special background mode for it when your bt device can wake up the app.

is iOS background mode needed if app works when suspended?

I need my iPhone app to do some tasks in the background when it's suspended, but I don't need to do any tasks after it's turned off. Do I need to settle UIBackgroundMode?
Yes, to execute code continuously in the background state, you need to register for a given UIBackgroundMode.
See here or here for a good source on this.
However if you just wish to perform a single background task (task completion), you don't need a background mode.
In response to your comment below, I will try to be clear:
In iOS, even in iOS 7, it's not possible to run arbitrary code when your application is in a background state indefinitely.
In simple English, - you can't just run any code you like in the background for as long as you like.
There are rules.
These rules have been relaxed somewhat in iOS 7, but it's still not totally unrestricted.
Consider your situation: You have a timer that wants to call a method on a continuous basis.
Now consider the UIBackgroundModes available (which allow you to run in the background in various situations):
audio - Only for audio based apps.
location - Only if you app is location aware, does specific location tasks
voip - VOIP (Skype etc)
fetch (Background fetch - a new iOS 7 API where the system gives you application moments to grab new content when it sees fit.
remote-notification - new in iOS 7, when the device receives a remote push notification with a certain payload, it will resume and execute a certain block of code.
newsstand-content - Only for newsstand apps
external-accessory - Only for external accessories to communicate with the device
bluetooth-peripheral Only for external BT accessories to communicate with the device (fitbit)
As you can see if you don't fall into one of these categories you can't use these modes.
If you misuse the modes Apple won't approve your application.
Finally we have 'Background task completion'
This is a way to use a UIBackgroundTask to execute any code you want in the background! Including timers that call methods! - One problem though...
This is supposed to be for 'task completion' (Facebook uploads that aren't complete, saving or processing data that should be done before the app suspends even though the user pressed the home button).
Sounds good, but you can only run in the background using this method for a maximum of 10 minutes. If you go over this time limit iOS will immediately kill your application.
So as you can see, there is no way for your application to be approved on the store and constantly run in the background with a timer that calls your method.
Sorry about that.
If you want to learn more check this out.
Use the location service and set NO location manager "pausesLocationUpdatesAutomatically" property.

How does the Navita TEM app get call log information?

How does Navita https://itunes.apple.com/us/app/navita-t.e.m.-personal/id590228620?mt=8
manage to display a call log?
If I swipe the app out of the task manager then it misses the calls, this indicates that it must presumably be using CTCallCenter's callEventHandler and is creating its own call log by saving the time/duration in response to the callEventHandler callbacks.
However if that is the case then how does it manage to do this in the background? I was under the impression that callEventHandler can only be used by apps in the foreground and not in the background?
The app is using location services, however even after disabling this it was still able to get information about the calls (provided the app isn't suspended). I though it might be using background location updates to keep itself primed to receive callEventHandler callbacks but apparently not.
The Navita app is additionally able to display call time and call duration.
The bounty will be awarded to an answer which contains sufficient, accurate and detailed information that enables me to emulate the behavior of the Navita app, specifically I must be able to write an app that can obtain the time and duration of a phone call that occurred while the app was not in the foreground, while the device's location services was turned off, and after the app had been in the background longer than the ~3 minutes granted by using beginBackgroundTaskWithExpirationHandler:
Here is what I observe with the Navita app that I want to be able to reproduce:
1) Run app
2) Task away from app
3) Go to device settings, privacy, and turn off Location Services.
4) Go to device settings, privacy, background app refresh and turn off for the app
5) Wait > 10 minutes to make sure the app is not still in the background as a consequence of using beginBackgroundTaskWithExpirationHandler:
6) Call the device from another phone, answer the phone call, then hang up.
7) Launch the app again and display the call time and duration
(This is iOS7 and unjailbroken)
Here is what I've found from Navita TEM disassembly and it's resources.
Application uses two background modes - location and audio. You can see it in the Info.plist file. When you enable phone calls logging application will also enable "alerts" and "Real-time" switches. When "alerts" enabled application infinitely loops in background "bg-sound.mp3" file which has no sound, it's just silence. Because of that it doesn't use hacks like this one How to get a call event using CTCallCenter:setCallEventHandler: that occurred while the app was suspended? . It's similar trick to location used in order to keep the app running in background and receive phone call events. Somehow this was not rejected from the AppStore.
If you are observing the call center while the app is in the background you get a set of updates when the app is brought back to the foreground. This set of data may not be as accurate as if the app had been mostly in the foreground but it does include quite a bit of info.

While(1) loop is not working in background in IOS

I was trying to run some services in the background so I struck the control in the background by using a while(1) loop in the background delegate for some time.
On the emulator it is working fine but on transfering it to my iPad, the app is crashing after going into the background.
Does the while(1) loop not work for on the device?
On emulator it is working fine but on transfering it to the Ipad device , the app is getting crashed after going in to the background.
If I interpret correctly this that you are writing, what I think is that your app gets killed on iOS devices simply because you are not allowed, except in a few spare cases, to run a thread in your app when the app is "in background" (i.e., after the user has "quit" it by clicking on the home button).
So, if I am right in my reading what is happening, either your app is in a specific class of
apps (see later), or the only thing you can do is "registering" a background thread to run for a limited amount of time after the app goes in the background.
Excerpt from Background Execution and Multitasking
Most apps are moved to the suspended state shortly after entering the background. Only apps that provide important services to the user are allowed to continue running for any amount of time.
As much as possible, you are encouraged to avoid executing in the background and let your app be suspended. If you find you need to perform background tasks, here are some guidelines for when that is appropriate:
You need to implement at least one of several specific user services.
You need to perform a single finite-length task.
You might be especially interested in the "Implementing Long-Running Background Tasks":
For tasks that require more execution time to implement, you must request specific permissions to run them in the background without their being suspended. In iOS, only specific app types are allowed to run in the background:
Apps that play audible content to the user while in the background, such as a music player app
Apps that keep users informed of their location at all times, such as a navigation app
Apps that support Voice over Internet Protocol (VoIP)
Newsstand apps that need to download and process new content
Apps that receive regular updates from external accessories

Resources