0

My goal is to advertise a beacon in background mode.

The expected result is: The beacon continue to advertise in background mode.

The actual result is: The beacon stop advertising in background mode.

What I've tried:

  1. Background task can extend time for 30 seconds but this is not a solution.
import Foundation
import CoreLocation
import CoreBluetooth

protocol BeaconBroadcaster {
    
    /// Broadcast to be find by scanner.
    /// - Parameters:
    ///   - uuid: used by broadcast scanner to find specific uuid
    ///   - major and minor: used by broadcast scanner to differentiate beacon with identical uuid
    func startBroadcasting(uuid: UUID, major: UInt16, minor: UInt16) -> BeaconBroadcasterStartBroadcastingEvent
    
    /// stop broadcaster
    func stopBroadcasting() -> BeaconBroadcasterStopBroadcastingEvent
}

class BeaconBroadcasterImpl: BeaconBroadcaster {
    private var peripheralManager = CBPeripheralManager()
    
    fileprivate init() {
#if DEBUG
        print("\(type(of: self)) \(#function)")
#endif
    }
    
    func startBroadcasting(uuid: UUID, major: UInt16, minor: UInt16) -> BeaconBroadcasterStartBroadcastingEvent {
        if peripheralManager.state == .poweredOff {
            return .BLUETOOTH_NOT_ENABLED
        }
        
        if peripheralManager.state == .unauthorized {
            return .BLUETOOTH_NOT_AUTHORIZED
        }
        
        if peripheralManager.state != .poweredOn {
            return .BLUETOOTH_NOT_AUTHORIZED
        }
        
        if peripheralManager.isAdvertising {
            _ = stopBroadcasting()
        }
        
        let bundleURL = Bundle.main.bundleIdentifier!
        let constraint = CLBeaconIdentityConstraint(uuid: uuid, major: major, minor: minor)
        let region = CLBeaconRegion(beaconIdentityConstraint: constraint, identifier: bundleURL)
        let peripheralData = region.peripheralData(withMeasuredPower: nil) as? [String: Any]
        peripheralManager.startAdvertising(peripheralData)
        
        return .BROADCASTER_IS_STARTING
    }
    
    func stopBroadcasting() -> BeaconBroadcasterStopBroadcastingEvent {
        if !peripheralManager.isAdvertising {
            return .BROADCASTER_HAS_ALREADY_STOPPED
        }
        
        peripheralManager.stopAdvertising()
        
        return .BROADCASTER_IS_STOPPING
    }
}

extension BeaconBroadcasterImpl {
    
    /// Usage: use force unwrap, it will always return non-nil value
    static var shared: BeaconBroadcaster? {
        get {
            if sharedClosure == nil {
                sharedClosure = BeaconBroadcasterImpl()
            }
            
            return sharedClosure
        }
        set {
            sharedClosure = newValue
        }
    }
    
    private static var sharedClosure: BeaconBroadcaster?
}

jnpdx
  • 45,847
  • 6
  • 64
  • 94
Jason Rich Darmawan
  • 1,607
  • 3
  • 14
  • 31

0 Answers0