swift – How can one use the iOS 17 CLMonitor APIs to monitor for an iBeacon?


It seems the new recommended way to work with Beacons in Swift is through a CLMonitor. As much as am I excited to be rid of delegate-style event handling, I can’t get a basic example working with the new style.

There seems to be very limited documentation on the matter with the only example being Apple’s from WWDC, which does not seem to be functional for me.

My code is as follows:

import Foundation
import CoreLocation

let monitorName = "BeaconMonitor"
let testBeaconId = UUID(uuidString: "EDFA3FFA-D80A-4C23-9104-11B5B0B8E8F3")!

@MainActor
public class ObservableMonitorModel: ObservableObject {
    private let manager: CLLocationManager
    
    public var monitor: CLMonitor?
    
    init() {
        self.manager = CLLocationManager()
        self.manager.requestWhenInUseAuthorization()
        self.manager.requestAlwaysAuthorization()
    }
    
    func startMonitoringConditions() {
        Task {
            monitor = await CLMonitor(monitorName)
            await monitor!.add(getBeaconIdentityCondition(), identifier: "Beacon")
            
            for identifier in await monitor!.identifiers {
                guard let lastEvent = await monitor!.record(for: identifier)?.lastEvent else { continue }
                print(identifier, lastEvent.state)
            }
            
            for try await event in await monitor!.events {
                print("Event", event.identifier, event)
                
            }
        }
    }
    
}

func getBeaconIdentityCondition() -> CLMonitor.BeaconIdentityCondition {
    CLMonitor.BeaconIdentityCondition(uuid: testBeaconId)
}

Then in ContentView.swift I have:

struct ContentView: View {
    @ObservedObject fileprivate var locationMonitor = ObservableMonitorModel()

    var body: some View {
        VStack {
            ...
        }.task {
            locationMonitor.startMonitoringConditions()
        }
    }
}

When ran with a spec-compliant BLE Beacon broadcasting the set UUID, the app only outputs Beacon CLMonitoringState, not anything from the for try await loop.

I’ve tried multiple iBeacons, like the ESP32, this Mac app, and commercial hardware from Amazon.

I have also tried swapping the Beacon monitor for a circular geography monitor, which works fine. The app has Bluetooth and Location permissions.

Latest articles

spot_imgspot_img

Related articles

Leave a reply

Please enter your comment!
Please enter your name here

spot_imgspot_img