Cordova: Scan for iBeacons / BLE in background mod

2019-05-31 10:41发布

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!

3条回答
倾城 Initia
2楼-- · 2019-05-31 11:03

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.

查看更多
够拽才男人
3楼-- · 2019-05-31 11:12

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()
查看更多
Lonely孤独者°
4楼-- · 2019-05-31 11:15

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

查看更多
登录 后发表回答