Receive signal from beacon while app is in the background - ios

I have a iOS app that interact with a beacon.
Also have a function to detect the signal from a beacon and if the signal is out of range I want to store something in the database (in this case core data)
func updateDistance(distance: CLProximity) {
UIView.animateWithDuration(1.0) { [unowned self] in
switch distance {
case .Unknown:
self.view.backgroundColor = UIColor.grayColor()
self.distanceReading.text = "No Beacon Signal Detected"
updateDatabaseWithLocation()
}
}
}
So the app works fine as long as the app is running in foreground.
My understanding is I can also have the app in the background when user not actively using the app and still get signal from beacon.
If so, how can I accomplish this task? I added the following to info.plist and still didn't work.Also is it possible to update the database as well?

You can only range beacons (which is what gives you access to the distance approximations) when the app is running. As soon you leave the app (press the home button, navigate to another app, etc.), iOS will suspend the app, and ranging will stop working. Continuous usage of Bluetooth radio in the background would drain the smartphone's battery quickly.
You can, however, have your app subscribe to be woken up into the background when the smartphone enters and exits range of a beacon (or a group of beacons). This is called region monitoring, and it's the same mechanism that geofencing uses.
Now, "enter" and "exit" events in and on themselves won't give you access to distance approximations. However, since iOS will wake your app into the background for a few seconds to handle these events, ranging will actually resume for the duration (assuming you haven't stopped it before the app got suspended), before iOS puts the app back to sleep again.
You can even extend the "few seconds" into up to a few minutes with a background execution task.
All of the above doesn't require the use of background modes—only the "always" authorization to use Location Services.
You can't ordinarily keep the app running in the background indefinitely with beacons. Background support is heavily regulated by Apple, and is only allowed, e.g., for navigation apps, or music apps. People do on occasion try using the "location" background mode to keep the app alive in the background (and thus capable of ranging beacons), and some even reported being able to get it past the review process, but that seems to be more of an exception than a rule.
Should you decide to give it a try anyway, you need to:
enable the "location" background mode,
set allowsBackgroundLocationUpdates to true on your CLLocationManager instance,
start regular location updates: startUpdatingLocation.
This should keep the app running in the background even if you leave it.

Related

Swift detect motion activity in background

I want to detect motion activity when app is pause (not stop).
I used this code and it working if user use app:
let isActivityAvailable = CMMotionActivityManager.isActivityAvailable()
if isActivityAvailable {
CMMotionActivityManager().startActivityUpdates(to: OperationQueue.main) { (motionActivity) in
if (motionActivity!.confidence.rawValue > 0) {
if (motionActivity?.walking)! {
print("User is walking")
}
}
}
}
Apps can be in several states:
Running in the foreground
Running in the background (actively performing background tasks)
Suspended (still in memory but not getting processor time.)
Terminated. Suspended apps can be terminated at any time without warning.
Only the first 2 states will receive motion updates. To quote the docs:
...updates are not delivered while your app is suspended.
Apps only stay in state 2 (running in background) for a few seconds when the user swaps them out or locks their phone, unless you ask for background time. Background time is limited to a short interval (3 minutes?) except for a small set of app types like music players and turn-by-turn navigation apps.
Because of these things, the short answer is no, you can't receive motion updates while your app "is pause" because paused becomes suspended.
For your own use (or perhaps internal enterprise use) you could set up an app as a music player and have it receive motion updates continuously, but such an app would be rejected in app store review.

How to BLE device will invoke the app, when app has terminated

I have a one BLE Device(Peripheral) and iOS Application which communicate to each other using CoreBluetooth.framework( connect, disconnect, subscribe, notify services). Here are the few scenario:
The app is foreground -> I am very easily connected with BLE device.
The app is in the background -> I get the callback and connect with the BLE device
The app is removed from the background (Kill the app) -> I am not getting any callback even I connect the device from iPhone Device-> Settings-> Bluetooth on -> Select Ble Device -> Connect.
I google and get State Preservation and Restoration will be invoked the app. After deep drive :
This also showing App Force Quit by the user , app will not relaunch or active using state preservation and restoration.
I read from this, this and this, have some points :
"If you need to execute code when your app isn’t running, there are several options open to you depending on what you’re trying to do.
- Background fetch will let your app run in the background for about 30 seconds at scheduled intervals. The goal of this is to fetch data and prepare your UI for when the app runs next.
- Push notifications let your app fetch fresh data from your server. You can make a message appear on the device if you want, but it’s not required – silent push notifications let you skip that part.
- Local notifications let you display an alert to the user, along with any media attachments you want and some options for the user to select from. If they choose those options then your app can be launched in the foreground or background to handle them."
I tried with Background Fetch, but it's also not awake when the application has been terminated.
My single objective to achieve is "When the application has terminated or killed by the user, Whenever BLE Device is connected the app should be invoked in foreground/background so that I will perform some operation like get the data from BLE Device and save it"
Using background modes in a project:
Other BackgroundModes also not gives any clue:
How can achieve this without using push notification or silent notification?
if anything in CoreBluetooth framework where the application awake after the termination, let me know?
The short answer is, you can't.
The documentation clearly states that your app will not be relaunched when it is explicitly killed by the user.
This is true for silent notifications as well - these will not wake your app up if the user had forced terminated your app (or the device battery state is below 20%, btw).
Your options for this are limited, and may include advising the user not to force kill your app, or using location based region detection to re-launch your app.
One of the tutorials you've linked shows an iBeacon example to detect going in and out of range of iBeacons, and when combined with background permission can relaunch your app, but again - this isn't explicitly what you've asked for and is not a real solution to the problem you describe.
Apple's logic is simple - if the user kills your app, the user doesn't want it to run again, which makes allot of sense.
The thing is, many users think that killing apps is the standard way to make their device more responsive, there's a big debate on this (what's worse? having the OS cold start apps or allowing apps to do funny stuff in the background with silent notifications, etc.) I won't go into that debate, that's just the way it is.
This is Abstract code to highlight the solution. You might need to tweak few things.
1> Create CLBeaconRegion with UUID start monitoring for that beacon
locationManager.requestAlwaysAuthorization()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
locationManager.allowsBackgroundLocationUpdates = true
locationManager.startUpdatingLocation()
locationManager.startMonitoringSignificantLocationChanges()
if let uuid = UUID(uuidString: "B9407F30-F5F8-466E-AFF9-25556B57FE6D") {
let beaconRegion = CLBeaconRegion(proximityUUID: uuid,identifier:"iBeacon")
beaconRegion.notifyOnExit = true
beaconRegion.notifyOnEntry = true
locationManager.startMonitoring(for: beaconRegion)
}
2> As per the document
If you begin monitoring a region and your app is subsequently
terminated, the system automatically relaunches it into the background
if the region boundary is crossed
Reference
3> Your peripheral should transmit as ibeacon who transmit same UUID (Same UUID for which you have created CLBeaconRegion)
You might need to play with few parameters of CLLocationManager and CLBeaconRegion but this should work in my opinion because in the past my apps have been successfully woken up from terminated state on iBeacon detection ....

can we get location updates in IOS swift in a regular intervel of time even when app is not running in foreground

I want to get location updates of the user in a regular interval of time even if the app is not running in foreground.
In most of the articles i have read, they said that the OS will forcefully stop or suspend the background service the app have started.
What i need is the app should regularly check the user location and when that location becomes greater than say 10Kms the app should trigger a local notification.
We were able to do the functionality correctly when the app is ran again by the user. But it wont work in background. And if we inegrated it as a background service , then it is causing the app to crash. :(
this part caught my attention after a long time of search
https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html#//apple_ref/doc/uid/TP40009497-CH2-SW8
As far as I understood, they say that the OS will wakeup the app to get the current location when it senses a change in location.
But I didnt get any helping tutorial to accomplish the same
These are the tutorials which I refered
Periodic iOS background location updates
How do I get a background location update every n minutes in my iOS application?
Getting user location every n minutes after app goes to background
iOS Not the typical background location tracking timer issue
iOS long-running background timer with "location" background mode
What i need is preferably a background service or something which does the job done which check of the current location calculate distance and makes a local notification.
But as far as i know all the background services will be suspended or killed by the OS within some time after the app is gone in background.
Please guys I am desperate, Its been 2 weeks i am on in its tail.
Building the same for Android was a piece of cake actually.
Any help ???
You can get background location updates easily, you need to enable "Location updates" under "Background Modes" section in capabilities.
You also need to request for Always Authorisation and finally add this
if #available(iOS 9.0, *) {
locationManager.allowsBackgroundLocationUpdates = true
}
Make sure "Location updates" is activated else the above code will lead to a crash.
Also, write the CLLocationManager Delegate Methods in your AppDelegate class as this would increases chances of those methods being called as mentioned on Raywenderlich Background Location tutorial

Refresh iBeacon state

I am newbie with iBeacon and need some help. Already found some useful info from other topics but still searching for answers.
Is there a way to receive notification about my state at position right after app is killed or after I switch ON bluetooth? Now I got notifications only after state changes.
Example: I need to have notification when I got to point 'A'. But I got there and realized that my bluetooth is OFF. I switched bluetooth ON and didn't get anything because iBeacon thought I am 'INSIDE' from beginning. This happens when app is not foreground (but not 100% times, sometimes iBeacon 'rescan' and send his state again).
I need to somehow manually refresh iBeacon state and get methods didDetermineState or didRangeBeacons to work. I tried to stop and start monitoring after app is killed to forces the notification, but doesn't seem it works. I know there is a way to get this 'refresh' after turning ON display, but it could be perfect to also get it in other situations when needed.
Lots of location and beacon events can wake up an app that is running in the background, but relatively few events are sent to apps that have been killed via the task switcher or were never launched since boot.
The only bluetooth events capable of launching a non running app are:
didEnterRegion (for CLBeaconRegions)
didExitRegion (for CLBeaconRegions)
Other events received only by foreground/background running apps:
didDetermineStateForRegion
CoreBluetooth device discovery
CoreBluetooth power state changes
The last one is the event you care about, but it just won't be sent to apps that are not running. One alternative may be to rely on other location events like Significant Location Change, which launches a non-running app when the user moves "significantly" (e.g. to the next cell tower). You could register for these events and check Bluetooth state at that time. This may be the best you can do.

Understanding iBeacon region monitoring latency and testing

In order to test region monitoring I have added some UILocalNotifications that gets triggered when the app is launched. I have also enabled background mode communicates with BLE accessories for the App I am using to test this.
Now, what I have observed is that it does not always get launched with the same time ranges (as Apple's documentation already anticipates there will be a certain latency to avoid false positives). However I am trying to test the overall iBeacon region monitoring reliability and for this reason I drafted some basic test cases:
Case 1:
Phone is switched off AND beacon is turned on (App is not running).
Phone is switched on
Expected result: I expect iOS to wake up app.
Actual result: this does not always happen immediately. It does after long long time (e.g. 20 minutes). Is there an official upper limit for this?
Case 2:
Phone is on AND beacon is turned off (App is not running).
Beacon is turned on
Expected result: I expect iOS to wake up app.
Actual result: It does usually happen.
Case 3:
Phone is on AND beacon is turned off (App is not running).
Beacon is turned on
Wait until app is woken up (background running).
Turn beacon off.
Wait until region is exited.
Kill App (whilst running in background).
Turn beacon on.
Wait until App is woken up (background running).
The above flow usually works. However I noticed that it works well when we wait until 5 occurs (region is exited and this event is detected by the app running in background).
Any suggestion or further use cases? I struggle in particular with case 1.

Resources