diff --git a/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEL2CAPClient.h b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEL2CAPClient.h index 4a98b817..3ca5607b 100644 --- a/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEL2CAPClient.h +++ b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEL2CAPClient.h @@ -42,23 +42,24 @@ typedef void (^GNCRequestDisconnectionHandler)(id peripheral); - (instancetype)init NS_UNAVAILABLE; /** - * Initializes the L2CAP client with a specified peripheral. + * Initializes the L2CAP client with a specified request disconnection handler. * - * @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)peripheral - requestDisconnectionHandler:(GNCRequestDisconnectionHandler)requestDisconnectionHandler; +- (instancetype)initWithRequestDisconnectionHandler: + (GNCRequestDisconnectionHandler)requestDisconnectionHandler; /** * Opens a L2CAP channel with the @c PSM. * * @param PSM The PSM to use for opening the L2CAP channel. + * @param peripheral The peripheral instance. * @param completionHandler Called on a private queue with the opened L2CAP stream if successfully * opened or an error if one has occurred. */ - (void)openL2CAPChannelWithPSM:(uint16_t)PSM + peripheral:(id)peripheral completionHandler:(GNCOpenL2CAPStreamCompletionHandler)completionHandler; /** Cancels an active or pending local connection to a peripheral. */ diff --git a/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEL2CAPClient.m b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEL2CAPClient.m index 78157ed0..3ec26863 100644 --- a/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEL2CAPClient.m +++ b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEL2CAPClient.m @@ -37,39 +37,41 @@ static char *const kGNCBLEL2CAPClientQueueLabel = "com.google.nearby.GNCBLEL2CAP GNCBLEL2CAPStream *_l2CAPStream; } -- (instancetype)initWithPeripheral:(id)peripheral - requestDisconnectionHandler:(GNCRequestDisconnectionHandler)requestDisconnectionHandler { - return [self initWithPeripheral:peripheral - queue:dispatch_queue_create(kGNCBLEL2CAPClientQueueLabel, - DISPATCH_QUEUE_SERIAL) - requestDisconnectionHandler:requestDisconnectionHandler]; +- (instancetype)initWithRequestDisconnectionHandler: + (GNCRequestDisconnectionHandler)requestDisconnectionHandler { + return + [self initWithQueue:dispatch_queue_create(kGNCBLEL2CAPClientQueueLabel, DISPATCH_QUEUE_SERIAL) + requestDisconnectionHandler:requestDisconnectionHandler]; }; // This is private and should only be used for tests. The provided peripheral must call // delegate methods on the main queue. -- (instancetype)initWithPeripheral:(id)peripheral - queue:(nullable dispatch_queue_t)queue - requestDisconnectionHandler:(GNCRequestDisconnectionHandler)requestDisconnectionHandler { +- (instancetype)initWithQueue:(nullable dispatch_queue_t)queue + requestDisconnectionHandler:(GNCRequestDisconnectionHandler)requestDisconnectionHandler { self = [super init]; if (self) { _queue = queue ?: dispatch_get_main_queue(); - _peripheral = peripheral; - _peripheral.peripheralDelegate = self; _requestDisconnectionHandler = requestDisconnectionHandler; } return self; }; - (void)openL2CAPChannelWithPSM:(uint16_t)PSM + peripheral:(id)peripheral completionHandler:(GNCOpenL2CAPStreamCompletionHandler)completionHandler { GTMLoggerInfo(@"[NEARBY] openL2CAPChannelWithPSM = %d", PSM); + _peripheral = peripheral; + _peripheral.peripheralDelegate = self; _completionHandler = [completionHandler copy]; [_peripheral openL2CAPChannel:(CBL2CAPPSM)PSM]; } - (void)disconnect { dispatch_async(_queue, ^{ - _requestDisconnectionHandler(_peripheral); + id localPeripheral = _peripheral; + _requestDisconnectionHandler(localPeripheral); + _peripheral = nil; + _peripheral.peripheralDelegate = nil; }); } @@ -130,15 +132,11 @@ static char *const kGNCBLEL2CAPClientQueueLabel = "com.google.nearby.GNCBLEL2CAP #pragma mark Private -- (void)shutDown { - _peripheral = nil; - _peripheral.peripheralDelegate = nil; -} - - (void)closeL2CAPChannel { [_l2CAPStream tearDown]; _l2CAPStream = nil; _l2CAPChannel = nil; + [self disconnect]; } @end diff --git a/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEMedium.m b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEMedium.m index 579954ab..6d5e711a 100644 --- a/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEMedium.m +++ b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEMedium.m @@ -277,10 +277,12 @@ static GNCBLEL2CAPServer *_Nonnull CreateL2CapServer( return; } if (!strongSelf->_l2capClient) { - strongSelf->_l2capClient = - [[GNCBLEL2CAPClient alloc] initWithPeripheral:remotePeripheral - requestDisconnectionHandler:^(id _Nonnull peripheral){ - }]; + strongSelf->_l2capClient = [[GNCBLEL2CAPClient alloc] + initWithRequestDisconnectionHandler:^(id _Nonnull peripheral) { + dispatch_async(_queue, ^{ + [_centralManager cancelPeripheralConnection:remotePeripheral]; + }); + }]; } strongSelf->_l2capStreamCompletionHandlers[remotePeripheral.identifier] = completionHandler; strongSelf->_l2capPSM = psm; @@ -412,6 +414,7 @@ static GNCBLEL2CAPServer *_Nonnull CreateL2CapServer( [_l2capClient openL2CAPChannelWithPSM:_l2capPSM + peripheral:remotePeripheral completionHandler:^(GNCBLEL2CAPStream *_Nullable stream, NSError *_Nullable error) { __typeof__(self) strongSelf = weakSelf; if (!strongSelf) { diff --git a/internal/platform/implementation/apple/Tests/GNCBLEL2CAPClient+Testing.h b/internal/platform/implementation/apple/Tests/GNCBLEL2CAPClient+Testing.h index f0078e11..b6f69ad4 100644 --- a/internal/platform/implementation/apple/Tests/GNCBLEL2CAPClient+Testing.h +++ b/internal/platform/implementation/apple/Tests/GNCBLEL2CAPClient+Testing.h @@ -23,18 +23,16 @@ NS_ASSUME_NONNULL_BEGIN @interface GNCBLEL2CAPClient (Testing) /** - * Creates a L2CAP client with a provided peripheral. + * Initializes the L2CAP client with a provided queue and request disconnection handler. * * This is only exposed for testing and can be used to inject a fake peripheral. * - * @param peripheral The peripheral instance. * @param queue The queue to run on, this must match the queue that the peripheral's delegate is * running on. Defaults to the main queue when @c nil. * @param requestDisconnectionHandler Called on a private queue with @c peripheral when the * connection to the peripheral should be cancelled. */ --(instancetype)initWithPeripheral:(id)peripheral - queue:(nullable dispatch_queue_t)queue +-(instancetype)initWithQueue:(nullable dispatch_queue_t)queue requestDisconnectionHandler:(GNCRequestDisconnectionHandler)requestDisconnectionHandler; @end diff --git a/internal/platform/implementation/apple/Tests/GNCBLEL2CAPClientTest.m b/internal/platform/implementation/apple/Tests/GNCBLEL2CAPClientTest.m index a53e5a2f..203ddac3 100644 --- a/internal/platform/implementation/apple/Tests/GNCBLEL2CAPClientTest.m +++ b/internal/platform/implementation/apple/Tests/GNCBLEL2CAPClientTest.m @@ -36,12 +36,11 @@ [super setUp]; self.fakePeripheral = [[GNCFakePeripheral alloc] init]; self.l2capClient = - [[GNCBLEL2CAPClient alloc] initWithPeripheral:self.fakePeripheral - queue:nil - requestDisconnectionHandler:^(id _Nonnull peripheral) { - XCTAssertNotNil(peripheral); - [self.requestDisconnectionHandlerExpectation fulfill]; - }]; + [[GNCBLEL2CAPClient alloc] initWithQueue:nil + requestDisconnectionHandler:^(id _Nonnull peripheral) { + XCTAssertNotNil(peripheral); + [self.requestDisconnectionHandlerExpectation fulfill]; + }]; } - (void)tearDown { @@ -56,6 +55,7 @@ uint16_t psm = 123; [self.l2capClient openL2CAPChannelWithPSM:psm + peripheral:self.fakePeripheral completionHandler:^(GNCBLEL2CAPStream *stream, NSError *error) { XCTAssertNil(error, @"Error should be nil"); [expectation fulfill]; @@ -72,6 +72,7 @@ self.fakePeripheral.openL2CAPChannelError = expectedError; [self.l2capClient openL2CAPChannelWithPSM:psm + peripheral:self.fakePeripheral completionHandler:^(GNCBLEL2CAPStream *stream, NSError *error) { XCTAssertNotNil(error, @"Error should not be nil"); XCTAssertEqualObjects(error, expectedError); @@ -84,6 +85,12 @@ - (void)testDisconnect { self.requestDisconnectionHandlerExpectation = [self expectationWithDescription:@"Request disconnection handler should be called"]; + uint16_t psm = 123; + + [self.l2capClient openL2CAPChannelWithPSM:psm + peripheral:self.fakePeripheral + completionHandler:^(GNCBLEL2CAPStream *stream, NSError *error){ + }]; [self.l2capClient disconnect]; diff --git a/internal/platform/implementation/apple/Tests/GNCBLEMediumTest.m b/internal/platform/implementation/apple/Tests/GNCBLEMediumTest.m index 80582d29..c9ab1562 100644 --- a/internal/platform/implementation/apple/Tests/GNCBLEMediumTest.m +++ b/internal/platform/implementation/apple/Tests/GNCBLEMediumTest.m @@ -313,10 +313,9 @@ static NSString *const kServiceUUID = @"0000FEF3-0000-1000-8000-00805F9B34FB"; GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init]; GNCBLEL2CAPClient *l2capClient = - [[GNCBLEL2CAPClient alloc] initWithPeripheral:fakePeripheral - queue:nil - requestDisconnectionHandler:^(id _Nonnull peripheral) { - }]; + [[GNCBLEL2CAPClient alloc] initWithQueue:nil + requestDisconnectionHandler:^(id _Nonnull peripheral){ + }]; [medium setL2CAPClient:l2capClient]; [medium openL2CAPChannelWithPSM:123 peripheral:fakePeripheral