Detect whether Apple Pencil is connected to an iPad Pro

后端 未结 2 584
南旧
南旧 2021-02-13 15:52

Is there an API that allows you to determine whether the Apple Pencil is connected to an iPad Pro? Looking over the 9.1 SDK I don\'t see anything that directly does this. Or per

2条回答
  •  佛祖请我去吃肉
    2021-02-13 16:33

    Took me quite a while to figure out that CBCentralManager's centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) is only called when the connection is initiated via its connect(_ peripheral: CBPeripheral, options: [String : Any]? = nil) function (yes, reading the docs helps :]).

    Since we have no callback for when devices have been connected to the device through the user (as is the case with Apple Pencil - I'd love to be proven wrong on this one btw), I had to resort to using a timer here.

    This is how it works:

    When you initialize ApplePencilReachability a timer is setup that checks for the availability of the pencil every second. If a pencil is found the timer gets invalidated, if bluetooth is turned off it also gets invalidated. When it's turned on again a new timer is created.

    I am not particularly proud of it but it works :-)

    import CoreBluetooth
    
    class ApplePencilReachability: NSObject, CBCentralManagerDelegate {
    
      private let centralManager = CBCentralManager()
      var pencilAvailabilityDidChangeClosure: ((_ isAvailable: Bool) -> Void)?
    
      var timer: Timer? {
        didSet {
          if oldValue !== timer { oldValue?.invalidate() }
        }
      }
    
      var isPencilAvailable = false {
        didSet { 
          guard oldValue != isPencilAvailable else { return }
          pencilAvailabilityDidChangeClosure?(isPencilAvailable)
        }
      }
    
      override init() {
        super.init()
        centralManager.delegate = self
        centralManagerDidUpdateState(centralManager) // can be powered-on already?
      }
      deinit { timer?.invalidate() }
    
      func centralManagerDidUpdateState(_ central: CBCentralManager) {
        if central.state == .poweredOn {
          timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { 
            [weak self] timer in // break retain-cycle
            self?.checkAvailability()
            if self == nil { timer.invalidate() }
          }
        } else {
          timer = nil
          isPencilAvailable = false
        }
      }
    
      private func checkAvailability() {
        let peripherals = centralManager.retrieveConnectedPeripherals(withServices: [CBUUID(string: "180A")])
        let oldPencilAvailability = isPencilAvailable
        isPencilAvailable = peripherals.contains(where: { $0.name == "Apple Pencil" })
        if isPencilAvailable {
          timer = nil // only if you want to stop once detected
        }
      }
    
    }
    

提交回复
热议问题