Подтвердить что ты не робот

Определите, подключен ли Apple Pencil к iPad Pro

Есть ли API, который позволяет вам определить, подключен ли Apple Pencil к iPad Pro? Оглядываясь на 9.1 SDK, я не вижу ничего, что непосредственно делает это. Или, возможно, это можно сделать с помощью API Bluetooth.

4b9b3361

Ответ 1

Я не могу найти фактическую документацию на Apple Pencil Bluetooth (и я не считаю, что он существует), но следующий код работает для Me & trade;.

Он проверяет подключенные устройства, которые рекламируют себя как поддерживающие "Информация об устройстве", а затем, если у любого из них есть имя "Apple" Карандаш".

PencilDetector.h

@import CoreBluetooth

@interface PencilDetector : NSObject <CBCentralManagerDelegate>

- (instancetype)init;

@end

PencilDetector.m

#include "PencilDetector.h"

@interface PencilDetector ()

@end

@implementation PencilDetector
{
  CBCentralManager* m_centralManager;
}

- (instancetype)init
{
  self = [super init];
  if (self != nil) {
    // Save a reference to the central manager. Without doing this, we never get
    // the call to centralManagerDidUpdateState method.
    m_centralManager = [[CBCentralManager alloc] initWithDelegate:self
                                                            queue:nil
                                                          options:nil];
  }

  return self;
}

- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
  if ([central state] == CBCentralManagerStatePoweredOn)
  {
    // Device information UUID
    NSArray* myArray = [NSArray arrayWithObject:[CBUUID UUIDWithString:@"180A"]];

    NSArray* peripherals =
      [m_centralManager retrieveConnectedPeripheralsWithServices:myArray];
    for (CBPeripheral* peripheral in peripherals)
    {
        if ([[peripheral name] isEqualToString:@"Apple Pencil"])
        {
            // The Apple pencil is connected
        }
    }
  }
}

@end

На практике следующий, более простой, синхронный код, который не ждет центральный администратор должен быть включен, прежде чем проверять подключенные устройства кажется, работает так же хорошо в моем тестировании. Однако в документации указано, что вы не должны вызывать любые методы в менеджере до тех пор, пока государство не обновится CBCentralManagerStatePoweredOn, поэтому более длинный код, вероятно, безопаснее.

Где угодно

m_centralManager = [[CBCentralManager alloc] initWithDelegate:nil
                                                        queue:nil
                                                      options:nil];

// Device information UUID
NSArray* myArray = [NSArray arrayWithObject:[CBUUID UUIDWithString:@"180A"]];

NSArray* peripherals =
  [m_centralManager retrieveConnectedPeripheralsWithServices:myArray];
for (CBPeripheral* peripheral in peripherals)
{
  if ([[peripheral name] isEqualToString:@"Apple Pencil"])
  {
    // The Apple pencil is connected
  }
}

Ответ 2

Мне потребовалось некоторое время, чтобы понять, что CBCentralManager centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) вызывается только тогда, когда соединение инициируется через его функцию connect(_ peripheral: CBPeripheral, options: [String : Any]? = nil) (да, чтение документов помогает:]).

Поскольку у нас нет обратного вызова, когда устройства были подключены к устройству через пользователя (как в случае с Apple Pencil - я бы хотел, чтобы это было неправильно в этом отношении), мне пришлось прибегнуть к использованию таймер здесь.

Вот как это работает:

При инициализации ApplePencilReachability устанавливается таймер, который проверяет доступность карандаша каждую секунду. Если карандаш найден, таймер становится недействительным, если Bluetooth выключен, он также становится недействительным. Когда он снова включается, создается новый таймер.

Я не особенно горжусь этим, но он работает: -)

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
    }
  }

}