Implement GattClient#Disconnect for Apple implementation of BLEv2

PiperOrigin-RevId: 679218551
This commit is contained in:
Nick Bourdakos
2024-09-26 11:09:30 -07:00
committed by Copybara-Service
parent dc35037fee
commit 1a87241ffd
10 changed files with 191 additions and 55 deletions
@@ -49,6 +49,14 @@ typedef void (^GNCGetCharacteristicCompletionHandler)(
typedef void (^GNCReadCharacteristicValueCompletionHandler)(NSData *_Nullable value,
NSError *_Nullable error);
/**
* A block to be invoked after a call to @c disconnect, requesting that the local connection to the
* remote peripheral be cancelled.
*
* @param peripheral The remote peripheral to disconnect from.
*/
typedef void (^GNCRequestDisconnectionHandler)(id<GNCPeripheral> peripheral);
/**
* An object that can be used to discover, explore, and interact with GATT services and
* characteristics available on a remote peripheral.
@@ -64,8 +72,11 @@ typedef void (^GNCReadCharacteristicValueCompletionHandler)(NSData *_Nullable va
* Initializes the GATT client with a specified peripheral.
*
* @param peripheral The peripheral instance.
* @param requestDisconnectionHandler Called on a private queue with @c peripheral when the
* connection to the peripheral should be cancelled.
*/
- (instancetype)initWithPeripheral:(id<GNCPeripheral>)peripheral;
- (instancetype)initWithPeripheral:(id<GNCPeripheral>)peripheral
requestDisconnectionHandler:(GNCRequestDisconnectionHandler)requestDisconnectionHandler;
/**
* Discovers the specified characteristics of a service.
@@ -112,6 +123,9 @@ typedef void (^GNCReadCharacteristicValueCompletionHandler)(NSData *_Nullable va
completionHandler:
(nullable GNCReadCharacteristicValueCompletionHandler)completionHandler;
/** Cancels an active or pending local connection to a peripheral. */
- (void)disconnect;
@end
NS_ASSUME_NONNULL_END
@@ -49,6 +49,7 @@ static NSError *AlreadyReadingCharacteristicError() {
@implementation GNCBLEGATTClient {
dispatch_queue_t _queue;
id<GNCPeripheral> _peripheral;
GNCRequestDisconnectionHandler _requestDisconnectionHandler;
/**
* A map of service UUIDs with each service holding a map of a list of characterisitcs to a
@@ -70,15 +71,18 @@ static NSError *AlreadyReadingCharacteristicError() {
*_readCharacteristicValueCompletionHandlers;
}
- (instancetype)initWithPeripheral:(id<GNCPeripheral>)peripheral {
return [self
initWithPeripheral:peripheral
queue:dispatch_queue_create(kGNCBLEGATTClientQueueLabel, DISPATCH_QUEUE_SERIAL)];
- (instancetype)initWithPeripheral:(id<GNCPeripheral>)peripheral
requestDisconnectionHandler:(GNCRequestDisconnectionHandler)requestDisconnectionHandler {
return [self initWithPeripheral:peripheral
queue:dispatch_queue_create(kGNCBLEGATTClientQueueLabel,
DISPATCH_QUEUE_SERIAL)
requestDisconnectionHandler:requestDisconnectionHandler];
};
// Private.
- (instancetype)initWithPeripheral:(id<GNCPeripheral>)peripheral
queue:(nullable dispatch_queue_t)queue {
queue:(nullable dispatch_queue_t)queue
requestDisconnectionHandler:(GNCRequestDisconnectionHandler)requestDisconnectionHandler {
self = [super init];
if (self) {
_queue = queue ?: dispatch_get_main_queue();
@@ -86,6 +90,7 @@ static NSError *AlreadyReadingCharacteristicError() {
_peripheral.peripheralDelegate = self;
_discoverCharacteristicsCompletionHandlers = [[NSMutableDictionary alloc] init];
_readCharacteristicValueCompletionHandlers = [[NSMutableDictionary alloc] init];
_requestDisconnectionHandler = requestDisconnectionHandler;
}
return self;
};
@@ -173,6 +178,12 @@ static NSError *AlreadyReadingCharacteristicError() {
});
}
- (void)disconnect {
dispatch_async(_queue, ^{
_requestDisconnectionHandler(_peripheral);
});
}
#pragma mark - Internal
- (CBCharacteristic *)synchronousCharacteristicWithUUID:(CBUUID *)characteristicUUID
@@ -245,7 +245,13 @@ static NSError *AlreadyScanningError() {
GNCGATTConnectionCompletionHandler handler = _connectionCompletionHandlers[peripheral.identifier];
_connectionCompletionHandlers[peripheral.identifier] = nil;
if (handler) {
GNCBLEGATTClient *client = [[GNCBLEGATTClient alloc] initWithPeripheral:peripheral];
GNCBLEGATTClient *client =
[[GNCBLEGATTClient alloc] initWithPeripheral:peripheral
requestDisconnectionHandler:^(id<GNCPeripheral> peripheral) {
dispatch_async(_queue, ^{
[_centralManager cancelPeripheralConnection:peripheral];
});
}];
handler(client, nil);
}
}
@@ -79,6 +79,21 @@ NS_ASSUME_NONNULL_BEGIN
- (void)connectPeripheral:(id<GNCPeripheral>)peripheral
options:(nullable NSDictionary<NSString *, id> *)options;
/**
* Cancels an active or pending local connection to a peripheral.
*
* This method is nonblocking, and any @c CBPeripheral class commands that are still pending to
* @c peripheral may not complete. Because other apps may still have a connection to the peripheral,
* canceling a local connection doesnt guarantee that the underlying physical link is immediately
* disconnected. From the apps perspective, however, the peripheral is effectively disconnected,
* and the central manager object calls the @c centralManager:didDisconnectPeripheral:error: method
* of its delegate object.
*
* @param peripheral The peripheral to which the central manager is either trying to connect or has
* already connected.
*/
- (void)cancelPeripheralConnection:(id<GNCPeripheral>)peripheral;
/** Asks the central manager to stop scanning for peripherals. */
- (void)stopScan;