I have implemented an cordova/ionic app (hybrid for iOS/Android) that scans for iBeacons in background mode and notifies the user, if a beacon is found. I am using following plugins:
- iBeacon Scanning: cordova-plugin-ibeacon by petermetz
- Background Mode:
cordova-plugin-background-mode by katzer
- Notification: cordova-plugin-local-notifications by katzer
This works good so far (on both iOS and Android). The problem here is, that Apple would reject my App form publishing to the App Store (see https://github.com/katzer/cordova-plugin-background-mode/issues/77).
An other problem is, that it seems like the background beacon scanning is consuming very much battery capacity. With this Background Plugin the complete App is running in the background and not just a specific function/service.
Does anyone of you know if there is a plugin for running tasks in background (or more specific: scanning for iBeacons in background), which works on iOS and Android and would be accepted by the App Stores? I haven't found any. If such a plugin is not available, do you think it would generally be possible to develop such a plugin? As far as I know, background services are available for both Android and iOS (native).
Thanks!
When it comes to iOS, this isn't really a Cordova-specific question. Apple does not allow ranging (scanning) for beacons in the background for more than a few minutes at a time without special permissions that require an extra hurdle to get approved in the AppStore. In order to get approved in the AppStore with constant background scanning for beacons, you have to convince Apple that your app is a navigation app. Read more here.
As for battery usage, yes, constant ranging for beacons does drain battery significantly. This is why Apple generally disallows apps from doing this in the background. The alternative is to use beacon monitoring APIs instead of beacon ranging APIs. Monitoring APIs alert you when beacons appear or disappear, and use either hardware assist or only periodic bluetooth scanning to save battery.
There are specific Cordova complications when it comes to background processing (mostly due to the need for the WebView to be active to process callbacks), but if you are planning on deploying to the AppStore, you must first solve the more fundamental issues above.
I'm facing the same issue also.I'm not a native app developer but i came to know that combining all this three plugins you will get desired result.
My concept is to notify mobile when beacon moves from the region in application background mode.
-Naitik
Sorry for the delay on response. I had this same problem some months ago and found no answer :(, I am just willing to share my findings
You can ussing cordova plugin only worry about android devices. When it comes to iOS you can use the beacon monitoring api.
You just need to import the cordoba project on xCode
You will find inside the project a file called AppDelegate.swift
before class initialization put this
import CoreLocation
after the class initialization you need to put the variables like this
class AppDelegate: UIResponder, UIApplicationDelegate {
var beaconManager:CLLocationManager!
var region:CLBeaconRegion!
Now press command + N or go to file > new > file
Create a new swift file, click next and give i ta name
Change the file content with this
import Foundation
import CoreLocation
import UserNotifications
extension AppDelegate:CLLocationManagerDelegate{
//here we will initialize our beacon monitoring manager,
//we will call this function later on the AppDelegate Main class
func initBeaconManager(){
//remember whe have defined our locationManager and region variable on AppDelegate Main Class
locationManager: CLLocationManager = CLLocationManager()
locationManager.delegate = self
//you will need to change these variables according to your becon configuration
let uuid = UUID(uuidString: "CHANGE ME YOUR BEACON UUID IF YOU DONT CHANGE IT IT WILL CRASH")!
let major = 123 //beacon major
let minor = 012 // beacon minor
let identifier = "some indentifier of your region that you like"
//you can define your region with just the uuid that way if you have more that one beacon it will work with just one region
//uncomment below if that´s the case
//let region = CLBeaconRegion(proximityUUID: uuid, identifier: identifier)
//in this case we will be ussing all variables major minor and uuid
region = CLBeaconRegion(proximityUUID: uuid, major: CLBeaconMajorValue(major), minor: CLBeaconMinorValue(minor), identifier: identifier)
//great now that we have defined our region we will start monitoring on that region
//first of all we make sure we have the correct permissions
let authorization = CLLocationManager.authorizationStatus()
switch authorization {
case .notDetermined:
//in case it is not authorized yet we will ask here for authorization
//the key is to request always authorization that way the enter and exit region callbacks will be called even if the app is killed or the phone restarted
locationManager.requestAlwaysAuthorization()
//after requesting for ahtorization we will get the authorization changed callback, there will be starting monitoring our region
case .denied, .restricted ,.authorizedWhenInUse:
//the user has denied the authorization we can make the user go to settings and enable it again
//but you can do that also ussing cordoba so... I just put in this case switch to commit that :D
break
case .authorizedAlways:
//we are goot to go now we can start monitoring
locationManager.startMonitoring(for: region)
}
if let uuid = UUID(uuidString: "B9407F30-F5F8-466E-AFF9-25556B57FE6D") {
let beaconRegion = CLBeaconRegion(
proximityUUID: uuid,
major: 100,
minor: 50,
identifier: "iBeacon")
locationManager.startMonitoring(for: beaconRegion)
}
}
//LOCATOIN MANAGER EXIT AND ENTER REGION
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
//notification when enter
let notificationTitle = "CHANGE ME"
let notificationBody = "CHANGE ME ENTER REGION"
sendNotification(title: notificationTitle, body: notificationBody)
}
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
//notification when leave
let notificationTitle = "CHANGE ME"
let notificationBody = "CHANGE ME EXIT REGION"
sendNotification(title: notificationTitle, body: notificationBody)
}
//Simple notification with only a custom title and body
func sendNotification(title:String,body:String){
if #available(iOS 10.0, *) {
let content = UNMutableNotificationContent()
content.title = title
content.body = body
content.sound = UNNotificationSound.default()
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.1, repeats: false)
let request = UNNotificationRequest(identifier: "enterNotification", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: { (error) in
// Handle error
})
} else {
let notification = UILocalNotification()
if #available(iOS 8.2, *) {
notification.alertTitle = title
}
notification.alertBody = body
notification.soundName = UILocalNotificationDefaultSoundName
UIApplication.shared.presentLocalNotificationNow(notification)
}
}
}
On the file comment you can find places that you need to change
Now return to AppDelegate file and put this inside the function
func application(_ application: UIApplication, didFinishLaunchingWithOptions ....
This will initialize all the functions you have wirtten on the extension
self.initBeaconManager()