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