beginBackgroundTaskWithExpirationHandler doesn't expire - ios

On connect i added this bit of code at the end of getting the user connected:
UIBackgroundTaskIdentifier myLongTask;
myLongTask = [[UIApplication sharedApplication]
beginBackgroundTaskWithExpirationHandler:^{
// If you're worried about exceeding 10 minutes, handle it here
}];
CFRunLoopRun();
[[UIApplication sharedApplication] endBackgroundTask:myLongTask];
I also set in build settings, application needs wifi. This is a basic client that uses a socket.
Before if i locked the iPad the internet died. Now i was expecting it to stay alive for 10 minutes after the iPad locks but for some reason it just stays on indefinitely so far. I've measured the internet being on over 30 minutes after i lock the phone and come back and unlock and my connection is still streaming chat.
I'm concerned this may not be legal app behavior for acceptance in app store though i did not set any special settings i was reading about that this is a VOIP app. I just used the beginBackgroundTaskWithExpirationHandler, and application requires internet. I'm also concerned about long term battery impact if indeed the application never really sleeps, though the server i'm connecting to would disconnect you if idle for 60 minutes so it would not stay connected indefinitely but still its a concern if this loop always runs even after a disconnect it could use battery. For example what if the user leaves the app and doesnt come back for over a week and the iPad is just sitting locked for a week would it use accelerated battery? My testing hasn't got that far yet as this is a new situation this morning that i have were internet wont turn off were before it shut the connection any time the screen locked.
Any suggestions? Anyone know why the app wont sleep after 10 minutes of a screen lock?
Mike

the os may kill you or it may not. the 10 minutes are more like a 'guideline' but the os may kill you earlier or later anyways.
but CFRunloopRun will run almost indevifinitly (well as long any source is attached or it is stopped). make sure it ends or you never end the bg task.
not forbidden but not cool!

This is a very strange way to setup a background task request. It is unusual to call CFRunLoopRun() manually this way as well. The fact that you do this on the main loop suggests that you're not using the standard UIApplicationMain() function. If not, then you may not be setting up the application correctly, and behaviors can be erratic. Have you tried using background tasks the normal way:
beginBackgroundTaskWithExpirationHandler:
Do the specific task you would like to run even if the program goes into the background
endBackgroundTask: when that task is done
The way you're doing it, endBackgroundTask: is likely never called.
EDIT: If your goal is to be allowed to run after going into the background for as long as the OS is willing to let you run (around 10 minutes), then call beginBackgroundTaskWithExpirationHandler: in applicationWillEnterBackground:. You don't need any special use of the runloop. You just need to tell the OS you'd like to keep going until it stops you.

Related

How to keep running iOS application (iOS 9+) in background till user changes wifi settings of iOS device

In my application, the user needs to connect the device wifi to another wifi via the iOS settings. I want my app to remain in the background for some time(like 5 min max) without getting suspended, until the user connects to the other network and returns to the application.
I observe that my application gets removed from background during switching the device wifi. The application doesn't remain active in the background.
How do I keep the iOS application (iOS 9+) in background for some time i.e 5 min?
Apps moving to the background are expected to put themselves into a
quiescent state as quickly as possible so that they can be suspended
by the system. If your app is in the middle of a task and needs a
little extra time to complete that task, it can call the
beginBackgroundTaskWithName:expirationHandler: or
beginBackgroundTaskWithExpirationHandler: method of the UIApplication
object to request some additional execution time. Calling either of
these methods delays the suspension of your app temporarily, giving it
a little extra time to finish its work. Upon completion of that work,
your app must call the endBackgroundTask: method to let the system
know that it is finished and can be suspended.
(source: https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html)
Read iOS Backgrounding with Tasks .
The time App will be in background in 10 minutes that is 600 seconds.
You can know time remaining using the code
NSLog(#"Time Remaining: %f", [[UIApplication sharedApplication] backgroundTimeRemaining]);
Since your need is just turning wifi on- It may take less than 10 minutes i think.
Hope my answer is Clear and Helpful.

App running in the background for 3 minutes

I have an app which maintains a socket connection with a server. When the application is backgrounded (Home button is tapped) this connection breaks, and when the user comes back reconnection takes around 5 seconds. Not too much, but still an annoyance.
This works perfectly, but I think I could improve the user experience if the app asked for background execution time with:
[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];
I get 3 minutes additional runtime here, and the socket can stay alive a little more. If the user returns in these 3 minutes then the there is no reconnection, the app can immediately be used again. (This happens quite often, because they just check their e-mail really fast, reply to a message etc... and immediately return to my app.)
This would definitely improve the user experience, and as I see some apps use this (like the IRC iOS client). The documentation clearly says though:
You should not use this method simply to keep your app running after it moves to the background.
I don't want to run longer than 3 minutes or fake to be a VoIP or Music player app. This would just be a minor user experience improvement. Can Apple reject an app because of this?
(For now let's ignore that the socket connection doesn't break immediately when the app is backgrounded.)
If appstore review team will find it, they will reject the binary. You have definite quote from documentation why you can't use it. Also, if you add background mode like your app is VoIP or Music player, but app is not such kind of application, it also can be rejected.

How long does it takes to start receiving location updates after iOS device reboot?

I have an app that does geofencing/beacon region monitoring. The app functions well in - foreground, background and killed state.
The problem: I have been noticing a delay in the beacon/geofence events(entry/exit) after I restart the phone(without killing the app) and do not launch the app manually upon restart. I only start getting the entry/exit events after 3-4 minutes of restart, even if I enter the region before.
Is it normal behaviour?
Thanks
This is normal. I have noticed this delay of several minutes since CoreLocation added iBeacon support in version 7. The exact amount of time varies from one hardware model to the next, and even between reboots on the same hardware model.
While it might be possible to statistically characterize the delay with repeated tests, this is very time consuming to do. In the end, there is nothing you can do about it anyway.

Should I call setMinimumBackgroundFetchInterval every time the app restarts?

I developed an app that uses background fetch. I set the minimum interval between updates to minimum:
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
I thought that this value is saved by the system, so I don't have to set it again when/if the app restarts.
However, I've just noticed that the last background fetch on one of my devices was two weeks ago. I know, that the interval between updates can vary, but I don't think that two weeks is normal. Especially considering the fact that it worked for several months, calling background update every 20-30 minutes.
Unfortunately, I couldn't find a way to get the MinimumBackgroundFetchInterval to check my theory (does anyone know how to get it by the way?). I only checked application.backgroundRefreshStatus, and it is equal to UIBackgroundRefreshStatusAvailable, but I think (I'm not sure) this only means that the user allows the app to use background updates.
Well, it turned out that NO, we don't need to call setMinimumBackgroundFetchInterval every time the app restarts.
I had an experiment: I set it to UIApplicationBackgroundFetchIntervalMinimum (turned the background fetch on), then shut the app down manually (via the task manager) and then restarted it, but didn't call to setMinimumBackgroundFetchInterval. The app continued to perform background fetches as it used to.
I hope, that this information will be helpful for someone, since it is not explicitly stated in the documentation (at least, I didn't see it). As for me, I have to find another possible reason why my app didn't work for two weeks.

How long does Apple permit a background task to run?

I have to upload an array of image files to database, therefore, I stumbled upon Apple's background execution guide to make sure the app still uploads the data when user suspends or terminates my app.
But in the desciption, it says giving it a little extra time to finish its work if we call beginBackgroundTaskWithName:expirationHandler: or beginBackgroundTaskWithExpirationHandler: to start a background task.
How long is little extra time precisely?
Correct me if I am wrong, but I have stumbled upon a perfect article from Xamarin that discusses iOS backgrounding feature.
I will simply break down to two parts, ios pre 7 and ios 7+:
iOS version pre 7
The answer is simply 600 seconds (10 minutes), reason is provided by
the article above.
iOS version 7+
The answer is that the time system allocates you is opportunistic. You
will have to use #Gary Riches's suggestion
NSLog(#"Time Remaining: %f", [[UIApplication sharedApplication] backgroundTimeRemaining]);
to find out. The reason for it being opportunistic is the way iOS 7+
handles background tasks is completely different, certainly optimised. To
be exact, It has an intermittent behaviour, and therefore, if you need
background tasks such as downloading a big chuck of data, it will be
much more effective if you use `NSURLSession` instead.
However, in my special case, I am uploading one single object that contains one file to be exact. I do not have to consider NSURLSession for uploading a small amount of data. And besides, it's uploading task, it can take as much time as it wants. :-)
For these TL;DR visitors, the answer above should be sufficient. For more details, please refer to the article above.
The amount of time will differ based on many different variables, but the value can be checked by referencing the backgroundTimeRemaining property on UIApplication:
NSLog(#"Time Remaining: %f", [[UIApplication sharedApplication] backgroundTimeRemaining]);
If you want to upload your files when app is in background, you should use Apple's background service. iOS will give your app time of approx. 3 minutes (based on some experience) for completing your task and then it will kill your app.
Apple allows longer run of the app in special cases. For that you will need to use UIBackgroundModes in your info.plist file. For more info on these special cases see table 3-1 on this link.
Here is a nice article that describes background task run time and how to achieve long running background task in iOS.
Theorically, you have 2/3 minutes to close the tasks you want to do in background, if you don't do it, your app can be killed.
After that, you can call 'beginBackgroundTaskWithExpirationHandler 'and you have to be prepared just in case the 'little extra time' that Apple gives is not enough for the tasks you need to finish.
EDIT:
When an iOS application goes to the background, are lengthy tasks paused?:
From the documentation:
Return from applicationDidEnterBackground(_:) as quickly as possible. Your implementation of this method has approximately five seconds to perform any tasks and return. If the method doesn’t return before time runs out, your app is terminated and purged from memory.
From Raywenderlich:
'Again, there are no guarantees and the API documentation doesn’t even give a ballpark number – so don’t rely on this number. You might get 5 minutes or 5 seconds, so your app needs to be prepared for anything!':
http://www.raywenderlich.com/29948/backgrounding-for-ios
How much time you get after your app gets backgrounded is determined by iOS. There are no guarantees on the time you’re granted, but you can always check the backgroundTimeRemaining property of UIApplication. This will tell you how much time you have left.
The general, observation-based consensus is that usually, you get 10 minutes. Again, there are no guarantees and the API documentation doesn’t even give a ballpark number – so don’t rely on this number. You might get 5 minutes or 5 seconds, so your app needs to be prepared for anything!
It is not fixed: in Xcode 10 and Swift4.1
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
print(UIApplication.shared.backgroundTimeRemaining)
}
OP1: 166.13057912699878 mean approx 2.7 min,
OP2: 177.4997792619979 mean approx 2.95 min

Resources