We are developing an app that should respond to an iBeacon and circular regions in the background.
Sometimes it works perfectly, but sometimes the beacon and circular region enter/exit stop suddenly.
In the app, we are using(in background mode)
Significant location updates
Beacon region monitoring
Circular region monitoring
Continuous location updates for some actions
Any idea? It seems to me that in the background regions detection sometimes stopped working suddenly
Could it be the problem?
After trial/error, testing, and conversations with Apple, I can confirm it's not a bug with region monitoring, it's a bug with Apple's new prewarming feature in iOS 15.
In a nutshell, iOS 15 will half-launch apps silently in the background that iOS believes the person will use. In our testing this happens about every half hour. It makes app launching feel faster because a bunch of the app is already loaded and ready to go.
If Apple prewarms your app, and the user doesn't fully launch it, and then a region monitor needs to notify your app, it won't happen. That's sometimes region monitoring alerts your app and sometimes it doesn't. If your app is "cold", it will work. If your app is in memory, it will work. If your app is in this prewarm state, you are dead in the water.
I have it from Apple that this is really multiple bugs, some fixed and some not yet. The notes in the iOS 15.2 betas also specifically mention this likely affects HealthKit too.
The solution that works around the bug is to detect in main.m when Apple is prewarming your app and exit. This doesn't permit your app to launch when Apple prewarms and forces your app to fully boot when the time comes.
Here's the code for inside the main() method inside main.m. Note that it's prudent to add an iOS version detection so when Apple does fix this it can eventually be phased out and removed.
double systemVersion = [[UIDevice currentDevice] systemVersion].doubleValue;
if (systemVersion >= 15.0) {
NSDictionary* environment = [[NSProcessInfo processInfo] environment];
BOOL prewarmed = false;
for (NSString *key in environment.allKeys) {
if ([key.lowercaseString containsString:#"prewarm"]) {
prewarmed = true;
break;
}
}
if (prewarmed) {
exit(0);
}
}
There have been two recent reports of region monitoring failing on iOS 15:
IOS 15 Ibeacon monitoring
iOS 15 does not awake app while entering BLE beacon region
The above are for CLBeaconRegion monitoring, but whatever problem exists may apply to CLCircularRegions as well.
I tried doing a controlled test in my answer to the second question above to reproduce this across an iOS 15 upgrade. I could not reproduce the problem. So this does not appear to be a universal issue.
You might try rebooting or reinstalling your app to see if these changes make a difference. Any updates based on the results of these tests would be welcome.
Related
Batter drain issue while the app is in the background
I've encountered this nasty situation with my work react native app, it drains up to 100% of the user's device battery in a day and not quite sure why.
The app, on newer devices, stays in the background for a long time (older devices don't have the memory and suspend it sooner). Trying to investigate the source of the issue but don't know where to start.
UPDATED
Seems the culprit was react-native-video, the pictureInPicture is unreliable and according to their docs
This function corresponds to the completion handler in Apple's restoreUserInterfaceForPictureInPictureStop. IMPORTANT: This function must be called after onRestoreUserInterfaceForPictureInPictureStop is called.
If pictureInPicture is unreliably set then the onRestoreUserInterfaceForPictureInPictureStop can't reliably be called. Disabling pictureInPicture has seemingly stopped the battery drain we've been experiencing.
My iOS app has BLE beacons detection in it. Which means If user has bluetooth and location on and if user enters the range of a beacon, system automatically awakes the app If it was not running (killed state).
This was working fine on iOS 14 and below. Yesterday I updated my device to iOS 15 and app no longer gets awoken while entering a ble beacon region even If I have enabled "Always" location permission in the settings.
Any thoughts ?
My tests show that iOS 15 successfully launching an app from a stopped state into the background on beacon region entry.
Test steps:
Install this app on my phone with iOS 14.8: https://github.com/davidgyoung/CoreLocationRegionLaunchDemo
Run the app, grant notification and location always permissions.
Go to settings and verify location permission is always
Turn on a beacon, verify an entry notification arrives. Then turn off the beacon, verify the exit notification arrives.
Reboot the phone. Wait 5 minutes. Turn on the beacon, then verify the entry notification arrives. Turn off the beacon and verify the exit notification arrives.
Upgrade to iOS 15.
Wait 5 mintues.
Turn on a beacon. Verify an entry notification arrives.
See screenshots -- sorry they are ugly, but I have to finish the giant download of XCode 13 before I can send screenshots directly to my computer.
After trial/error, testing, and conversations with Apple, I can confirm it's not a bug with region monitoring, it's a bug with Apple's new prewarming feature in iOS 15.
In a nutshell, iOS 15 will half-launch apps silently in the background that iOS believes the person will use. In our testing this happens about every half hour. It makes app launching feel faster because a bunch of the app is already loaded and ready to go.
If Apple prewarms your app, and the user doesn't fully launch it, and then a region monitor needs to notify your app, it won't happen. That's sometimes region monitoring alerts your app and sometimes it doesn't. If your app is "cold", it will work. If your app is in memory, it will work. If your app is in this prewarm state, you are dead in the water.
Rebooting the whole phone works, because you're evicting any app in a prewarmed state.
I have it from Apple that this is really multiple bugs, some fixed and some not yet. The notes in the iOS 15.2 betas also specifically mention this likely affects HealthKit too.
The solution that works around the bug is to detect in main.m when Apple is prewarming your app and exit. This doesn't permit your app to launch when Apple prewarms and forces your app to fully boot when the time comes.
Here's the code for inside the main() method inside main.m. Note that it's prudent to add an iOS version detection so when Apple does fix this it can eventually be phased out and removed.
double systemVersion = [[UIDevice currentDevice] systemVersion].doubleValue;
if (systemVersion >= 15.0) {
NSDictionary* environment = [[NSProcessInfo processInfo] environment];
BOOL prewarmed = false;
for (NSString *key in environment.allKeys) {
if ([key.lowercaseString containsString:#"prewarm"]) {
prewarmed = true;
break;
}
}
if (prewarmed) {
exit(0);
}
}
It's weird, in my case, reboot seems to solve the problem.
Starting from iOS 12 the CLLocationManager doesn't run endless anymore in the background. The app get's terminated without a crashlog at random times. This was working fine before iOS 12.
To demonstrate this problem I've created an sample app here
The demo app just launches an CLLocationManager and keep this running in the background. While running on the background we keep track of it by logging it. The problem is that the app get terminated by iOS. The demo app is created to demonstrate this problem.
Steps to reproduce
Run the app on the device
Grand access to locationmanager
Put the app to the background
Wait for 1-48hours
Result:
The app is terminated
App is terminated without any reason after random time.
Expected result:
The app is still running.
How it should work
This is confirmed by an Apple engineer:
Once the CLLocationManager updates are started in the foreground and you did all the work to have it running in the background, the location updates should run endless in the background until:
app is force quit
device is rebooted
app stops location updates
app releases the CLLocationManager object
app crashes
iOS terminates the app due to memory shortage,
the locationManager object is released, overreleased, or overwritten. You should make sure that your view controller is not being instantiated, which then resets the locationController class. If that happens when the app is in the background, you will restart updates, which will cause the app to be eventually suspended. You should make sure the locationController is a singleton.
app is crashing. Check to see if there are crash logs on the device you are testing
iOS is terminating the app due to memory shortage. In this case, you will find JetsamEvent logs on the device that shows your app being terminated. You can check the timestamps and locate the one that is around the time your app stopped working.
Updated answer:
Apple fixed this bug in iOS 12.2 beta 2 (16E5191d)
Original analyse and bug detection:
Together with Apple Developer Technical Support we have analyzed this issue with Sysdiagnose files. Following these guidelines you can install profiles to have more logging on your device. I don't know exactly how these logs work and where to find this issue, but Apple did this for me and came with this first analyse:
On the suspension event you observed on 2018/10/22 01:01:12:587, this
is what I see (about a minute after your last activity logging)
[CllocationManag:2725] Terminating with description:
{
owner = ;
target = rw.sp.flitsmeister.frameworks.CllocationManagerBackgroundTest; }
This is basically saing that your app was terminated, because the
system needed drive space, and killed a bunch of apps so it can delete
their /tmp and /Library/Caches directories. I have seen this process
to be a little more aggressive in iOS 12, but seeing you are on a
256GB device, and have ~179 GB free after the cleanup, I am finding it
hard to believe this was justified.
After sending some more sysdiagnose and reproduction cases Apple did his best to analyse and ended with the following conclusion:
Unfortunately I don’t bring good news.
It turned out that, currently in iOS 12 there is a new mechanism that
will terminate long running background apps periodically as the system
needs to free resources. At this time, this process is a bit too
aggressive, and I am working with the relevant teams to get this to
behave better.
So, at this point, I would like you to file a bug report. Explain the
symptoms. And make sure you upload the sysdiagnose files along with
the bug report. (I already sent yours in, but it doesn’t hurt to have
the new ones as well). And let me know the bug number please.
So this means that currently in iOS 12 you app won't run endless on the background. I've filled in a bug report, the number is 45581276 and will try to keep this thread updated.
I tried clearing out the /tmp and /Library/Caches directories when the app goes in the background without any change in behavior. I also tried the same periodically when the app processing background locations without any change as well.
all day I tested the monitoring of beacons my app does. in general it works ok:
notifications in foreground work
notifications in background work
BUT
after a reboot it doesn't work until I launch ANY app that uses BluetoothLE
after I do that it works fine for my app as well!
But if I set UIBackgroundMode location in my plist though, my app gets region notifications just fine even after a reboot.
So... is that it? or whats the deal here? :D
this is under ios 7.1.1 btw
The code is very minimal:
https://github.com/RadiusNetworks/ibeacon-background-demo/blob/master/BackgroundDemo/BDAppDelegate.m
I did two things:
First, I reduced the time it took the app to launch >> mainly by doing stuff only when the app moves to the foreground. That was Step 1 but for the real app I was working on that alone was only half the solution
I then found out that the application in question tried to access the keychain in the background while the device was locked I moved that to a later point too and BING it worked!
My app is an emergency app. It will be used by people in emergency and disasters.
It's possible that they got stuck in situations where they just don't have the time to enter or draw their password on the lock screen, launch the app and push a button. Is it possible that my app can ask the OS to launch the app if user throw their iPhone up in the air or shake it vigorously or something else.
What I wish to achieve by this ?
I want that OS launches my app in background if the user say shake his/her iPhone vigorously. Once launched my app will make a network request and keep running in background for short time.
PS:I think it's possible with the accelerometer.
Accelerometer will not work because Apple doesn't allow background processes opening apps. In your case, user must be opening the app by himself/herself manually. (PS. As far as I know, it's possible in Android)
iOS background tasking problems aside:
Apple don't allow apps that encourage the user to do things that might damage their iOS device. So your 'throw in the air' idea is out.
As for shaking the device -- this just isn't practical. What if the device gets shaken by accident? You've then got false alarms to deal with.
The crux of the issue is that something that triggers an emergency response should be a deliberate action which is hard to do trigger by accident.
This cannot work - and here's why.
Your app would need to run in background to handle motion events. Apps running in background can get killed at any time, i.e. if memory gets low. There might be some restrictions about running and and resource usage as well.
An app in the background cannot bring itself to the front.
Launching from a locked screen would bring great security risks.
Throwing into the air seems like a gesture that can easily be triggered by accident.
I must admit that I'm pretty happy that those apps are not allowed on the AppStore - as it would open many doors that I'd like to see kept close.