Search code examples
androidiosibeaconaltbeaconandroid-ibeacon

iOS CLLocationManager Not Detecting Android Beacon Library iBeacon Signal Sent From Android


App Purpose

  1. Transmit a Beacon signal from iOS and detect that signal on Android & iOS Devices.
  2. Transmit a Beacon signal from Android and detect that signal on Android & iOS Devices.

Technologies

Android: Android Beacon Library.

  • AltBeacon signal sent and received between Android devices (for better accuracy)
  • iBeacon signal sent from iOS and received on Android
  • iBeacon signal sent from Android and received on iOS (Not Working)

iOS: CoreLocation CLLocationManager iBeacon.

  • iBeacon signal sent from iOS and received on iOS
  • iBeacon signal sent from iOS and received on Android
  • iBeacon signal sent from Android and received on iOS (Not Working)

The Problem

  • Using the same UUID across both platforms, when transmitting an iBeacon signal from iOS it is detected on another iOS device using the CLLocationManager delegate method
    locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion)

Using the same UUID to transmit an iBeacon signal from Android using the Android Beacon Library, the beacon is not detected by the above CLLocationManager delegate method on iOS.

The Code

  • To increase the chance of detection, I have removed the requirement for Major and Minor values on the iOS side to prevent the possibility of iOS filtering out the Beacon signal due to Major and Minor value mismatch.
  • Yes I have tried adding the Major and Minor values to no avail.
  • I have tried Ranging the beacon using the following method as well:
    func startRangingBeacons(satisfying constraint: CLBeaconIdentityConstraint)

Detecting on iOS

    var locationManager: CLLocationManager!
    var localBeaconUUID = "578f4eba-a16e-11ea-bb37-0242ac130002"
    let beaconIdentifier = "MyBeacon"

    override func viewDidLoad() {
        locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager.requestAlwaysAuthorization()
   }

    func startScanning() {
        let uuid = UUID(uuidString: localBeaconUUID)!
        let beaconRegion = CLBeaconRegion(uuid: uuid, identifier: beaconIdentifier)
        locationManager.startMonitoring(for: beaconRegion)
        locationManager.startRangingBeacons(in: beaconRegion)
    }

    func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {
        print("Ranged beacons: \(beacons.count)")
    }

Transmitting iBeacon on Android

    private val uuid = "578f4eba-a16e-11ea-bb37-0242ac130002"

    fun transmitBeacon() {
        val beacon = Beacon.Builder()
                .setId1(uuid)
                .setId2("1")
                .setId3("1")
                .setManufacturer(0x004c)
                .setTxPower(-59)
                .setDataFields(listOf(0L))
                .build()
        val beaconParser = BeaconParser()
                .setBeaconLayout("m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24")
        val beaconTransmitter = BeaconTransmitter(applicationContext, beaconParser)
        beaconTransmitter.startAdvertising(beacon)
    }

Solution

  • The layout shown here:

    val beaconParser = BeaconParser()
                    .setBeaconLayout("m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24")
    

    is for AltBeacon, which iOS devices cannot detect via CoreBluetooth. You can only use that iOS API to detect iBeacon, which has this layout:

    val beaconParser = BeaconParser()
                    .setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24")
    

    In an earlier answer in another forum, I noted that the OP was using a layout with a data field added and suggested he remove it, but did not realize the more fundamental issue that that the layout in the question uses the matching bytes beac which only works for AltBeacon format. For iBeacon, you must match on 0215