My app uses CoreBluetooth to connect a BLE device, also adds the UIBackgroundModes (the value "bluetooth-central") in the info.plist. When the app into the background, app can continue to read the RSSI Value from a connected device. But app be killed in the background every time after several minutes. I uses instruments tool to test the live bytes, the total bytes about 12MB. Test the app in iphone4s,iphone5,iphone5s, there are such problems. So I don't know how to resolve it? My app requires the long time running in the background. Everyone has other ideas?
I think you should start a background task.
UIApplication *app = [UIApplication sharedApplication];
UIBackgroundTaskIdentifier taskIdentifier = [app beginBackgroundTaskWithExpirationHandler:^{
// Cleanup before closing app
}];
Related
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.
My app does the intended operations when I use Simulate Background Fetch in the Debug tab in Xcode, however, when the app is running on my phone nothing works.
Has this happened to someone before? How did you resolve it?
I'm currently using Swift 2.2 and Xcode 7.3
Did you edit the schema in Run mode for the Launch due to a Background Fetch Event
iOS Background Fetch Not Working Even Though Correct Background Mode Configured
iOS won't allow any app to run in the background unless the app ask for it and it will allow it to run for 10mins only to register for background execution:
- (void)applicationDidEnterBackground:(UIApplication *)application {
UIBackgroundTaskIdentifier identifier;
identifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:identifier];
}];
}
I have developed IBeacon App. When the app is in background mode and I enter the beacon region the UILocalNotification is triggered. But the thing is that if I kill the app the notification still triggers. I use locationMgr.RequestAlwaysAuthorization (); to catch the location change when the app is in background. I have written background-safe task to enlarge my background time on iPhone.
I have tried to use UIApplication.SharedApplication.ApplicationState but it returns true when the app is in background only, not terminated.
I use locationMgr.RequestAlwaysAuthorization (); since DidEnterRegion is called only with location set to ALWAYS.
In a word I am searching for the solution how to monitor EnterRegion&ExitRegion only in background and active mode. NOT WHEN THE APP IS KILLED
Before iOS 7.1 this was the default behavior of iOS, and everybody complained about it. Since iOS 7.1, beacon monitoring will launch apps even if they are killed.
What you need is a way to detect if an app has previously been killed when it is launched again so you can suppress notifications. Unfortunately, I am unaware of any way to do this.
There are several reasons why an app would be terminated (not running):
because the user actively terminated it (double-tap on home button, swipe app up)
because the OS needed the memory, and terminated it
because the OS updated the app, and terminated it
because the device was rebooted, and the app was not launched yet
Do you want to avoid notifications in all cases, or only in the first one?
If you want to avoid notifications in all cases, you can try removing the local notification in your AppDelegate's applicationWillTerminate: method (or an observer for the UIApplicationWillTerminateNotification notification):
- (void)applicationWillTerminate:(UIApplication *)application
{
[application cancelLocalNotification:<insert here the notification you saved>];
}
(you may alternatively use cancelAllLocalNotifications, or search for the notification using scheduledLocalNotifications).
If you only want to avoid those notifications in the first case, I'm afraid I'm not aware of any way to detect the user having actively terminated the app.
I'm trying to get an app running indefinitely.. I'm developing an internal app, so apple approval doesnt matter.
I've tried a few different things, including simulating a voip app using this tutorial..
http://www.raywenderlich.com/29948/backgrounding-for-ios
Eventually I ran into this code snippet online
[application beginBackgroundTaskWithExpirationHandler:^{}];
I place this in beginBackgroundTaskWithExpirationHandler and then call a slow-looping function inside of my app delegate in application:didFinishLaunchingWithOptions
-(void)caller{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
NSTimeInterval timeRemaining = [UIApplication sharedApplication].backgroundTimeRemaining;
NSLog(#"%f", timeRemaining);
[self caller];
});
}
this logs background time remaining every 3 seconds. it does this when i exit my app.. i see a countdown from 180 (3 minutes) to eventually 0
then it just keeps logging 0 indefinitely. I would figure if background time reaches zero, then my process wouldnt execute.
Anyone have any idea whats going on here?
If you use beginBackgroundTaskWithExpirationHandler and start the app from Xcode, that will alter the behavior of this UIBackgroundTaskIdentifier (Xcode will keep the app alive). If you see the log messages showing up in Xcode's debugging console, that means the app was started on the device via Xcode.
Now that the app is installed on the device, stop it (either by hitting the "stop" button in Xcode or by manually terminating the app via Springboard on the device). Once you've confirmed the app isn't running, you can now run it again by tapping the app icon on the device itself. It should start, not linked to Xcode in any way.
Even though the app is now not running via Xcode, though, you can still monitor the progress of what you logged, by going to Xcode's "Device Organizer", and open up the actual device's console. I suspect you'll see the background task expire, like you expected it to.
I am triggering a background fetch by using the content-available flag on a push notification. I have the fetch and remote-notification UIBackgroundModes enabled.
Here is the implementation I am using in my AppDelegate.m:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
NSLog(#"Remote Notification Recieved");
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = #"Looks like i got a notification - fetch thingy";
[application presentLocalNotificationNow:notification];
completionHandler(UIBackgroundFetchResultNewData);
}
When the app is running in the background, it works fine. (The notification is received and the app triggered the "looks like i got a notification" local notification, as the code above should do).
However, when the app is not running and a push notification is received with the content-available flag, the app is not launched and the didRecieveRemoteNotification delegate method is never called.
The WWDC Video Whats New With Multitasking (#204 from WWDC 2013) shows this:
It says that the application is "launched into background" when a push notification is received with the content-available flag.
Why is my app not launching into the background?
So the real question is:
Will iOS perform background tasks after the user has force-quit the app?
UPDATE2:
You can achieve this using the new PushKit framework, introduced in iOS 8. Though PushKit is used for VoIP. So your usage should be for VoIP related otherwise there is risk of app rejection. (See this answer).
UDPDATE1:
The documentation has been clarified for iOS8. The documentation can be read here. Here is a relevant excerpt:
Use this method to process incoming remote notifications for your app.
Unlike the application:didReceiveRemoteNotification: method, which is
called only when your app is running in the foreground, the system
calls this method when your app is running in the foreground or
background. In addition, if you enabled the remote notifications
background mode, the system launches your app (or wakes it from the
suspended state) and puts it in the background state when a push
notification arrives. However, the system does not automatically
launch your app if the user has force-quit it. In that situation, the
user must relaunch your app or restart the device before the system
attempts to launch your app automatically again.
Although this was not made clear by the WWDC video, a quick search on the developer forums turned this up:
https://devforums.apple.com/message/873265#873265 (login required)
Also keep in mind that if you kill your app from the app switcher
(i.e. swiping up to kill the app) then the OS will never relaunch the
app regardless of push notification or background fetch. In this case
the user has to manually relaunch the app once and then from that
point forward the background activities will be invoked. -pmarcos
That post was by an Apple employee so I think i can trust that this information is correct.
So it looks like when the app is killed from the app switcher (by swiping up), the app will never be launched, even for scheduled background fetches.
You can change your target's launch settings in "Manage Scheme" to Wait for <app>.app to be launched manually, which allows you debug by setting a breakpoint in application: didReceiveRemoteNotification: fetchCompletionHandler: and sending the push notification to trigger the background launch.
I'm not sure it'll solve the issue, but it may assist you with debugging for now.
The answer is YES, but shouldn't use 'Background Fetch' or 'Remote notification'. PushKit is the answer you desire.
In summary, PushKit, the new framework in ios 8, is the new push notification mechanism which can silently launch your app into the background with no visual alert prompt even your app was killed by swiping out from app switcher, amazingly you even cannot see it from app switcher.
PushKit reference from Apple:
The PushKit framework provides the classes for your iOS apps to
receive pushes from remote servers. Pushes can be of one of two types:
standard and VoIP. Standard pushes can deliver notifications just as
in previous versions of iOS. VoIP pushes provide additional
functionality on top of the standard push that is needed to VoIP apps
to perform on-demand processing of the push before displaying a
notification to the user.
To deploy this new feature, please refer to this tutorial: https://zeropush.com/guide/guide-to-pushkit-and-voip - I've tested it on my device and it works as expected.
Actually if you need to test background fetch you need to enable one option in scheme:
Another way how you can test it:
Here is full information about this new feature:
http://www.objc.io/issue-5/multitasking.html
I've been trying different variants of this for days, and I thought for a day I had it re-launching the app in the background, even when the user swiped to kill, but no I can't replicate that behavior.
It's unfortunate that the behavior is quite different than before. On iOS 6, if you killed the app from the jiggling icons, it would still get re-awoken on SLC triggers. Now, if you kill by swiping, that doesn't happen.
It's a different behavior, and the user, who would continue to get useful information from our app if they had killed it on iOS 6, now will not.
We need to nudge our users to re-open the app now if they have swiped to kill it and are still expecting some of the notification behavior that we used to give them. I'm worried this won't be obvious to users when they swipe an app away. They may, after all, be basically cleaning up or wanting to rearrange the apps that are shown minimized.
This might help you
In most cases, the system does not relaunch apps after they are force
quit by the user. One exception is location apps, which in iOS 8 and
later are relaunched after being force quit by the user. In other
cases, though, the user must launch the app explicitly or reboot the
device before the app can be launched automatically into the
background by the system. When password protection is enabled on the
device, the system does not launch an app in the background before the
user first unlocks the device.
Source:
https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
For iOS13
For background pushes in iOS13, you must set below parameters:
apns-priority = 5
apns-push-type = background
//Required for WatchOS
//Highly recommended for Other platforms
The video link: https://developer.apple.com/videos/play/wwdc2019/707/