I thought I had the whole bluetooth restoration thing working (acting as a central), then I tried the following:
1 - Peripheral sends single bluetooth packet every 1 second
2 - At random time, I kill app (either using the debugger stop, or another app to eat all the memory)
3 - Check if restoration took place
This worked about 80% of the time and the errors were seemingly random.
After two days I was able to reliably reproduce the problem:
1 - Peripheral sends two packets 1000 ms apart
2 - Kill the app programatically (kill(getpid(),SIGKILL) some delta after the first packet (100ms,200ms...) which is some delta before the next packet (900ms, 800ms)
|--PKT-------850ms------KILL--150ms--PKT--|
3 - Second packet arrives and wakes the app up
What I found is that if the time between app termination and the next packet arriving is greater than about 150ms, restoration takes place as it should 100% of the time.
If the time between app termination and the next packet arriving is less than about 150ms, if I open the app manually within 10 seconds, restoration takes place 100% of the time. If I open the app manually after more than 10 seconds, it's as though no restoration took place. Also, once the app is killed, I watch the bluetooth symbol in the status bar and after exactly 10 seconds the connection is dropped.
Testing took place on an iPhone 4s running 8.1 and then 8.2.
This seems like a bug... I can provide my code if that helps however I've stripped it back to the bare minimum delegate implementations. I've tried putting the central manager on a different queue to no avail. This is real issue for my product as it relies upon session-based, background bluetooth tracking. Any thoughts?
This seems to be resolve in iOS 9+
Related
I have an application with background fetch capability. It was one of the first features implemented, and it was working like a charm - calling performFetchWithCompletionHandler every specified time interval (10 minutes).
Later in development, I noticed that this app does not performFetch at all - it was left running for weekend, and it did not fetch even once, while preferred interval was set as 10 minutes.
There was no changes to any of the related code, and I checked that it is set up correctly:
"background fetch" background mode - check
call setMinimumBackgroundFetchInterval - check (straight in appDidFinishLaunching, 10 * 60)
implement performFetchWithCompletionHandler - check
I can trigger fetch via Xcode debug tools, but there is no single call to app while left alone.
I had checked that iOS setting for background refresh is set to "ON" - both global setting (wifi and cellular) and per-app setting.
I did try reinstalling application, changing appID, even purging iPhone completely - nothing did not help.
The most intriguing part is that background fetch in the same build is still working for some testers. All of them have the same latest build, but most of them have no background fetch, while some are still updating in background.
I did not notice any correlation with iOS version, device family, test flight or local build variants or something like that:
iPhone 11 Pro, iOS 13.2.3, TestFlight - works
iPhone 11, iOS 13.3.1, TF - does not work
iPhone 8+, iOS 13.2, TF - works
iPhone SE, iOS 13.3.1, Local - does not work
iPhone 6, iOS 12.4.5, TF - does not work
My next step was to try reverting changes since last build with successful background fetch. Most notable change that happened in that time, was implementation of bundled WatchOS companion app - but how can that break background fetch?
Anyway, reverting source code did not help either.
Even more - I did try to create a simple background fetch example application, pure Xcode template with only three changes for background fetch (mentioned early) - that did not work too.
I am aware, that there is BackgroundTasks API now in iOS - but unfortunately, I have to support older devices with iOS 12 at best. Still, I did try that API too, using BGAppRefreshTask - that did not work too, but I suppose, it has the same underlying logic as old background fetch.
App does not consume a lot of resources - it has around 15 Mb RAM footprint on average, and execution time is at most 5 seconds - only one file download request with timeout of 10 seconds - just in case.
App is not terminated because of resources pressure, or because user force-quit it.
Also, I made sure completion handler is called in time, right after download ends.
The question is:
Am I really missing some step from background fetch implementation? Is it possible to break environment to this extent? If so, how can I find out what is causing all these issues?
Or: it is OK to not have a single bgFetch in weeks? (at this moment some devices did not bgFetch in weeks)
It seems like older versions of iOS allowed your app to run for 10 minutes in the background. Now it seems like iOS only allows your app to run for a maximum of 3 minutes. I haven't found any documentation mentioning when, or in which versions, this changed, or any estimates provided by Apple for how long your app can run in the background.
I need to be able to run in the background, because my app is connected to an external device via TCP. I already know about the hacks you can do with VOIP and playing silent audio (both will get your app rejected).
Is there anything I can do to get my app to keep running in the background longer than 3 minutes?
We haven’t had the old 10 minute window for years so that is simply no longer applicable. That was reduced to 3 minutes in OS 7, and further reduced to 30 seconds in iOS 13. (There is a new concept of background tasks, for running tasks longer than 30 seconds, but the the OS will run these at its own discretion, e.g. at night, when the user is charging their device, so that’s not really applicable here).
The short answer to your question is that you cannot submit apps to the store that run in the background indefinitely unless it’s one of a very limited list of permitted background modes.
If you can go to the “Signing & Capabilities” tab of your target and add “Background Modes” and you can see the list of alternatives:
So, with the caveat that you cannot do precisely what you asked, here are a few observations:
The “External accessory communication” background mode (see ExternalAccessory) seems promising, but that’s for bluetooth or wired connections only. So unless you can refactor/reengineer how your devices communicates, that is likely not a viable solution.
There’s an interesting question of whether just keeping the app running in the foreground might be helpful (e.g. judicious use of idleTimerDisabled). I know this solves a different problem (and should be used only where essential), but perhaps it’s option for you.
If your external device is Internet-enabled and you want it to inform the app of some event, perhaps you can have it communicate its intent to some web service that then triggers an APNS push notification that your device can receive.
Bottom line, you can’t do what you ask, but if you edit your question with more details about the nature of the device and what your iOS app wants to do with that device, we might be able to provide better counsel. But in answer to the general question “can I just keep app running perpetually in the background”, the answer is “no.”
i am developing a Swift based App for iOS 8.3 and i observed that the App starts very very slow and seems to stall in the App loading process. The App slows donwn before any of my code is executed. As matter of fact, only one thread is active, only 60k memory are used, the CPU is not busy. See attached Screenshot.
The App waits for about 20-30 seconds and continues as expected without any exceptions or error messages.
All this happens because there are Security checks added by the apple.
This is not applicable for not only iOS devices but applicable for all MAC devices as well.
For any change in files there will be security, signature checks gets performed.
Depending on the machine(iPhone/Mac), internet speed it takes times to get completed.
Any subsequent call to same (no recompile, modified) file does not observe this issue.
When testing a VOIP or a background fetch application, testing against background termination and launch is vital to see if the desired outcome is achieved. Right now, launching 28 applications including five games doesn't show any applications being killed due to memory hogs. The five games are NBA GM, CEASAR SLOTS, STELLA WARS, CRASH DRIVE 2, WATER 2.
What needs to be checked is, if any applications get killed on low memory conditions. Any ideas on triggering that kind of condition?
(VOIP apps won't be killed if the socket is active, but why aren't any applications getting killed?)
If your goal is to test how the app recovers from sudden termination (as opposed to how it handles the termination) then the easiest way to kill the app is to stop the debugging session with xcode.
Just Build And Run while the app is running, and you get an instant recovery test.
I'm working on an iOS app that ideally needs to run the location services in the background. I've tested the significant location, and that isn't accurate enough. The accurate location is perfect, but this consumes far too much battery life to make the app viable.
To get around this battery issue I thought I'd found a solution that uses NSTimer inside UIApplication:beginBackgroundTaskWithExpirationHandler:. This turns the location on and then instantly off again, which triggers a location update and resets the backgroundTimeRemaining.
However, this solution still drains a lot of battery – 15%-20% every 3-4 hours – even when the location is only turned on for one second every 9 minutes. The app is not running anything else in the background aside from this one timer. I've even tried releasing all of the views when entering the background to make sure there is nothing sitting and consuming the battery.
Checking inside instruments, I found the app is using 0.0% of the CPU and 14 MB of memory while in this waiting state. I'm at a bit of a loss at this point as to the cause, especially since running the GPS for 1 second every 540 seconds does not provide an appreciable reduction in battery consumption, compared to running it 24/7.
I've started compiling the following questions, which might contribute to the problem, and I'm hoping somebody has an answer or an idea...
Does running an app in this way stop the phone from entering some sort of low power mode?
Does starting the GPS use huge amounts of power?
Does the GPS keep running for a period of time even after turning off?
Yes, WWDC 2011 Session 312 "iOS Performance and Power Optimization with Instruments" covers this at about the 45 minute mark.
When you finish using the GPS it can remain active for up to 10 seconds, and active radios both wake the device and while active prevent the device from 'sleeping'.
You'll be able to see this using the 'Energy Diagnostics' template in Instruments.