Well, I want to know about app 'capabilities' when app receives memory warnings.
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
DDLogVerbose(#"applicationDidReceiveMemoryWarning");
[self executeTasks];
}
Could bluetooth connections be established? ( [central connectPeripheral:perihperal options:nil] )
Could bluetooth peripherals be scanned? ( scan started at this point )
Which kinds of background tasks could be executed?
My concerns:
I put establishConnections code in this applicationDidReceiveMemoryWarning handler. This code tries to establish connections to peripherals by known uids ([central connectPeripheral:perihperal options:nil]).
I thought that this functionality could be restricted and app would be rejected.
UPD:
Am I right about core bluetooth long-time usage?
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application; // try to clean up as much memory as possible. next step is to terminate app
So, If background service will be terminated, I can put 'establish connections' code inside didReceiveMemoryWarning preventing loosing connections. After that system kills service and take care about these connections as 'events for reviving my service from sleep when devices appear nearby'
There are a few questions in here. I can only answer the first.
applicationDidReceiveMemoryWarning is what it looks like and nothing more: a message from the operating system that free memory is in short supply. You can do whatever you want in response to it, or nothing at all. You can allocate an array of a million ints if you want.
But when the operating system can no longer allocate your app as much memory as it requires, your app will be terminated. Memory warnings are just a nicety you get before this occurs, and ideally you can take some action to free up memory.
Related
I'm using BLE connection and app needs to run in background forever. For now background mode working, but limited, after few hours system kills app without any notifications and appDelegate methods calls. I checked ram usage, and it not depend, system kills app when ram usage 60mb, and when 200mb. Also app periodically sent POST requests to server(every minute) and using location services. How to extend execution time? Is it possible to run app forever(if user not using other apps)?
The answer is NO, iOS is doing dark magic to optimise resources usage and we can't do anything about it.
When putting my app in the background, then running a bunch of other apps one after the other, it will eventually close my app due to phone memory management. This is understandable. My question is, can anything be done to notify the user A) The app closed because of memory and needs to be booted back up. OR B) Have some sort memory watcher to when the phone memory is getting low to alert the user?
Are either of these possible? Are any other options available?
This is understandable
Understandable but not necessary in the short term. You cannot prevent your app from eventually being terminated, but you should be doing everything you can to keep it off the "short list" of apps to be terminated when memory is needed, by shedding memory usage as you go into the background.
can anything be done to notify the user A) The app closed because of memory and needs to be booted back up
No. You cannot "notify the user" when your app has been backgrounded and suspended, because it has been suspended — it isn't running. You can't do anything at all. No code is actually being executed. You are like a frozen corpse. Unlike the corpse, you can be revived and brought back to life, but that is entirely up the user, who must summon you to the front again.
Your job in this respect is to make it, as much as possible, not matter whether or not the app was terminated while in suspension. If you were not terminated, you'll be revived in exactly the state you were in when you went into the background. Well, then see to it that if you are launched from scratch because you were terminated, you also return to the state you were in when you went into the background.
I know the answer is nominally "no", but I mean really—what if the app goes into the background (with BTLE background processing enabled)? For 24 hours? Across an app update?
Under the heading "Reconnecting to Peripherals", this Apple documentation describes a reconnection workflow that first tries to reconnect to previously paired peripherals found via retrievePeripheralsWithIdentifiers: but then starts scanning again if you fail to connect. How do you know when to give up on connect-ing to a previously found peripheral if there is no formal timeout? How do you know when to start/keep scanning if the idea is to re-connect to a previously found BTLE device whenever you move back into proximity to it, without the user necessarily interacting with your app?
Also, a note further down that page says that some BTLE devices might invent a random identifier for themselves every time they're powered on, so even though you find some previously paired peripherals from retrievePeripheralsWithIdentifiers: you might not be able to connect to them as their names have changed. Do any BTLE devices do that in practice? That's nuts!
This is a tricky one to answer. The CoreBluetooth framework itself does not have an official timeout on connect requests. In fact it will try to connect the peripheral for as long as possible. But how long is that?
Well, unfortunately this is not something that is very well defined. You can be pretty confident that the connection will not time out while the app is in the foreground, but as soon as you involve connections in the background then things are not so funny any more. Obviously, like you mention, the pending connection will not remain after a phone reboot, etc.. which is fine since no user would expect the app to still be running after a reboot anyway. Regarding long running pending connections, you will find in Apple’s documentation that they tell you to opt-in for State Preservation and Restoration in order to make sure that the pending connections are properly kept while the app is suspended and eventually terminated. This would be good if it worked as advertised, but unfortunately it does not. After many years of working with this I have found that it is nearly impossible to get a reliable background pending connection on iOS. I have reported many bugs on this topic but so far none have been resolved.
There are a few issues in particular that I think you should pay extra attention to:
State Preservation and Restoration will completely stop working if a Bluetooth-state-change event happens while your app is in the terminated state. This essentially means that if the bluetooth chip gets reset for any reason (ex by toggling bluetooth/flight mode/etc..) then your app will never be relaunched again by Core Bluetooth whenever the peripheral is advertising within range. The reason for this is because all pending connections that have been set by your app will be cleared whenever the bluetooth chip is restarted. The problem with this is that your app will not be relaunched to be notified of this change, so the pending connections will never be recovered. So your app will think that the peripherals will connect, while in fact they will not. To me this one is the most serious issue and it alone makes CoreBluetooth extremely unreliable.
Sometimes the framework gets ”stuck” in a bad state (possibly by an internal race-condition or similar). This can happen randomly, but you can pretty easily reproduce this by calling connectPeripheral immediately in the didFailToConnect or didDisconnect callback. When this happen the ”connection state” property is set to “connecting” when a pending connection is in fact not set. To avoid this I have found that you should wait at least around 20ms before connecting, for example using a dispatch_after or something.
The framework internally uses XPC connections for interprocess communication in order to deliver bluetooth event. On some occasions this will break for whatever reason and the connection will be lost. I don’t know why this happens, but whenever it happens state preservation will stop working and you will manually have to relaunch the app to recover from it. Sometimes I manages to catch this in the device sysdiagnose logs...
Using an iPhone 7 and at the same time having an Apple Watch (paired the phone) will completely break all reconnects from behind the lock screen in case the Watch is not currently connected (out of range/flight mode/low battery/or any other reason). This is particularly bad since it was introduced recently! But it looks like the Apple Watch for some reason has "priority" over other bluetooth peripherals.
These are from the top of my head, but there are other issues as well. Regarding random addresses, most often these peripheral use so called ”random resolvable” addresses. This means that they appear random but in fact they can be resolved using an IRK (Identity Resolving Key) which is usually shared during initial bluetooth bonding. Devices that use completely random addresses are to my knowledge not very common.
Problem: I need to remain disconnected from a BLE peripheral but send data it's data to a server for processing as often as possible, as it is potentially time-critical. In other words, I want to connect every so often and send the synced data to an API, while remaining disconnected at all other times to save battery life.
Failed Attempt: Setting the UIBackgroundModes field of my app's Info.plist file to bluetooth-central only gives me background execution while I am connected. I want to remain disconnected, but reconnect at predefined intervals, as well as schedule an alarm from background mode.
It's possible: I've noticed that the FitBit Flex app has an option in the settings to enable syncing in the background. I am not sure if it ever disconnects from my Flex while it is in range, but judging its so-small-I'd-lose-it battery size, I'm guessing it does not remain connected.
I know I've already accepted an answer for this (sorry!), but I've found a solution:
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:60*5]; // Every 5 minutes, minimum
in:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
and adding fetch to UIBackgroundModes, which iOS then calls:
- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler
every 15-240 minutes (yeah, it varies a lot, but it's better than nothing). Every time I am called to perform a fetch, I connect to the peripheral, sync and send its data to the server, then disconnect. Since I'm sending this data from the BLE peripheral to a server for processing/storage, I'm presuming that this is a legitimate (AppStore worthy) use of fetch.
CAVEAT: application:performFetchWithCompletionHandler: will not be called until iOS establishes a user usage pattern for the app. In other words, you need to keep the app around (not delete it) for about 24 hours or so before the application:performFetch... method gets called. Boy, did it take a while to figure that out!
UPDATE: Apple has accepted my app that used this solution (approved May 2014).
You can't. A backgrounded app cannot start any transactions, it can only react to incoming requests (data notifications, connection events...) In the background the application is effectively not running and even in case of BLE events it has only 8 seconds to go back to sleep, otherwise it is completely terminated for breaking the policy.
The only case when your app can stay alive for a while is when it uses the beginBackgroundTaskWithName:expirationHandler: API. But even in that case it has only 10 minutes to complete or it gets killed.
If you want to synchronize while in background, then the transaction must be started on the external peripheral's side. Easiest is to stay connected and send a notification to the central every once in a while. That will wake it up and it can proceed with reading the characteristics it needs. But there are several other ways to implement it. The final solution has to be designed to best meet your needs. If you have a concrete idea, then please submit it as a separate question.
https://developer.apple.com/hardwaredrivers/BluetoothDesignGuidelines.pdf
I'm pretty sure you guys have seen this, but just in case you haven't. Perhaps on the BLE Peripheral end you can save power by increasing the connection interval (page 22).
I am using core location framework inside my application and I set the location string in UIBackgroundMode or Required background modes(in Xcode 4.2) for getting the updated location from didUpdateToLocation method when app is running in background and also sending this updated location to server by hitting the specific link inside didUpdateToLocation method of core location framework.
My question is that will the app be terminated after some time when running in background or not?
No, there is no specific time defined for this.But app will definitely terminate based upon certain parameter - battery drain, memory footprint issue etc.
In developer documentation it is clearly mentioned - "The system keeps suspended apps in memory for as long as possible, removing them only when the amount of free memory gets low. Remaining in memory means that subsequent launches of your app are much faster."
Go through this for complete details -
http://developer.apple.com/library/ios/#DOCUMENTATION/iPhone/Conceptual/iPhoneOSProgrammingGuide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html
I am sure it is not useful for the author because the question was asked in June 2012 and I am giving an answer in June 2019. This answer maybe is useful for other users.
I am posting this answer because Everyone is said that it is OS default behaviour, We can not change it....bla....bla.
Recently, I was working with the same requirement. After 2-3 week hard
work, I did it. For other users, I create a helper class for it. My
app will never be killed by OS until the location tracking enabled.
You can also verify that OS will never kill this app tracking app
Use HSLocationManager for infinite location tracking in the active and inactive state.
Refer my app which is available in the app store(App will never kill by OS if location tracking is enabled)
Location manager that allows getting background location updates every
n seconds with desired location accuracy.
Advantage:
OS will never kill our app if the location manager is currently
running.
Give periodically location update when it required(range is between 2 -
170 seconds (limited by max allowed background task time))
Customizable location accuracy and time period.
Low memory consumption(Singleton class)
iOS app may get terminated due to following reasons:
Watchdog Timeout
As you’re probably aware, since iOS 4.x, most of the time when you
quit an iOS app, the app isn’t terminated – instead, it’s sent to
the background.
However, there are times when the OS will terminate your app and
generate a crash log if the app didn’t respond fast enough. These
events correspond with the implementation of the following
UIApplicationDelegate methods:
- application:didFinishLaunchingWithOptions:
- applicationWillResignActive:
- applicationDidEnterBackground:
- applicationWillEnterForeground:
- applicationDidBecomeActive:
- applicationWillTerminate:
In all of the above methods, the app gets a limited amount of time
to finish its processing. If the app takes too long, the OS will
terminate the app.
User Force-Quit
iOS 4.x supports multitasking. If an app blocks the UI and stops
responding, the user can double-tap the Home button from the Home
screen and terminate the app.
Note: You may have noticed that when you double-tap the Home button,
you also get a list of all the applications you’ve run in the past.
Those apps are not necessarily running, nor are they necessarily
suspended.
Usually an app gets about 10 minutes to stay in the background once
the user hits the Home button, and then it gets terminated
automatically by the OS. So the list of apps that you see by
double-tapping the Home button is only a list of past app runs.
Low Memory Termination
When subclassing UIViewController, you may have noticed the
didReceiveMemoryWarning method.
Any app that is running in the foreground has the highest priority in
terms of accessing and using memory. However, that does not mean the
app gets all the available memory on the device – each app gets a
portion of the available memory.
When total memory consumption hits a certain level, the OS sends out a
UIApplicationDidReceiveMemoryWarningNotification notification. At the
same time, didReceiveMemoryWarning is invoked for the app.
At this point, so that your app continues to run properly, the OS
begins terminating apps in the background to free some memory. Once
all background apps are terminated, if your app still needs more
memory, the OS terminates your app.
I have seen that the background location updates will work for several hours. But if I go to a place without reception the device will stop to send GPS updates it wont start when I go to a place with reception. This occurs after approximately 30min.
But if I add this, in iOS6, the app won't terminate
[locationManager setPausesLocationUpdatesAutomatically:NO];
Quick answer is pretty much no. Read below though for in depth.
Since multitasking has been enabled on iOS devices that a)your app gets allocated amount of memory and b)the device limits the amount of tasks, that is applications using memory, that occur at any given time. If you take an iOS device and open several apps you'll begin to notice that the app you opened first may have been terminated and reload from the viewDidLoad.
Generally it's safe to say if your app is a recently opened app (or even on a phone where someone clears the multitasking menu often) that the device will not terminate your application in the background.