Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions BLECombineKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@
39BE8C9C245D7394004F73DD /* BLECombineKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 39AC63C4245D07A70024D677 /* BLECombineKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
39D66B5225A5FD8000449587 /* StandardBLEPeripheral.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D66B5125A5FD8000449587 /* StandardBLEPeripheral.swift */; };
39D66B5725A5FE7F00449587 /* Array+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D66B5625A5FE7F00449587 /* Array+Extensions.swift */; };
39DE680A25A03A8900EABBE9 /* BLEPeripheralBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39DE680925A03A8900EABBE9 /* BLEPeripheralBuilder.swift */; };
39DE681125A03F3700EABBE9 /* MockBLEPeripheralBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39DE680D25A03F1C00EABBE9 /* MockBLEPeripheralBuilder.swift */; };
39DE680A25A03A8900EABBE9 /* BLEPeripheralProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39DE680925A03A8900EABBE9 /* BLEPeripheralProvider.swift */; };
39DE681125A03F3700EABBE9 /* MockBLEPeripheralProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39DE680D25A03F1C00EABBE9 /* MockBLEPeripheralProvider.swift */; };
39DE681925A049FD00EABBE9 /* MockCBCentralManagerWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39DE681825A049FD00EABBE9 /* MockCBCentralManagerWrapper.swift */; };
39E7B6FC245ED1010065044C /* CharacteristicsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39E7B6FB245ED1010065044C /* CharacteristicsView.swift */; };
39E7B6FE245ED11E0065044C /* CharacteristicsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39E7B6FD245ED11E0065044C /* CharacteristicsViewModel.swift */; };
Expand Down Expand Up @@ -130,8 +130,8 @@
39BE8C95245D6E16004F73DD /* ServicesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServicesViewModel.swift; sourceTree = "<group>"; };
39D66B5125A5FD8000449587 /* StandardBLEPeripheral.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StandardBLEPeripheral.swift; sourceTree = "<group>"; };
39D66B5625A5FE7F00449587 /* Array+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Extensions.swift"; sourceTree = "<group>"; };
39DE680925A03A8900EABBE9 /* BLEPeripheralBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BLEPeripheralBuilder.swift; sourceTree = "<group>"; };
39DE680D25A03F1C00EABBE9 /* MockBLEPeripheralBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockBLEPeripheralBuilder.swift; sourceTree = "<group>"; };
39DE680925A03A8900EABBE9 /* BLEPeripheralProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BLEPeripheralProvider.swift; sourceTree = "<group>"; };
39DE680D25A03F1C00EABBE9 /* MockBLEPeripheralProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockBLEPeripheralProvider.swift; sourceTree = "<group>"; };
39DE681825A049FD00EABBE9 /* MockCBCentralManagerWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCBCentralManagerWrapper.swift; sourceTree = "<group>"; };
39E7B6FB245ED1010065044C /* CharacteristicsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacteristicsView.swift; sourceTree = "<group>"; };
39E7B6FD245ED11E0065044C /* CharacteristicsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacteristicsViewModel.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -229,7 +229,7 @@
39AC63E8245D12A80024D677 /* BLEPeripheral.swift */,
39AC63E9245D12A90024D677 /* BLEPeripheralDelegate.swift */,
39AC63EA245D12A90024D677 /* BLEPeripheralResult.swift */,
39DE680925A03A8900EABBE9 /* BLEPeripheralBuilder.swift */,
39DE680925A03A8900EABBE9 /* BLEPeripheralProvider.swift */,
39D66B5125A5FD8000449587 /* StandardBLEPeripheral.swift */,
);
path = Peripheral;
Expand Down Expand Up @@ -284,7 +284,7 @@
children = (
39AC63FC245D13350024D677 /* MockBLECentralManager.swift */,
39AC63FB245D13350024D677 /* BLEPeripheralMocks.swift */,
39DE680D25A03F1C00EABBE9 /* MockBLEPeripheralBuilder.swift */,
39DE680D25A03F1C00EABBE9 /* MockBLEPeripheralProvider.swift */,
39DE681825A049FD00EABBE9 /* MockCBCentralManagerWrapper.swift */,
);
path = Mocks;
Expand Down Expand Up @@ -532,7 +532,7 @@
39AC63F4245D12D00024D677 /* ManagerState.swift in Sources */,
39BE8C92245D5E54004F73DD /* BLEScanResult.swift in Sources */,
39AC63EC245D12A90024D677 /* BLEPeripheralDelegate.swift in Sources */,
39DE680A25A03A8900EABBE9 /* BLEPeripheralBuilder.swift in Sources */,
39DE680A25A03A8900EABBE9 /* BLEPeripheralProvider.swift in Sources */,
39D66B5225A5FD8000449587 /* StandardBLEPeripheral.swift in Sources */,
39AC63ED245D12A90024D677 /* BLEPeripheralResult.swift in Sources */,
39D66B5725A5FE7F00449587 /* Array+Extensions.swift in Sources */,
Expand All @@ -555,7 +555,7 @@
39AC63FE245D13350024D677 /* BLEPeripheralMocks.swift in Sources */,
39B65AE32463ABEB00E96FDE /* BLECombineKitTests.swift in Sources */,
39AC63FF245D13350024D677 /* MockBLECentralManager.swift in Sources */,
39DE681125A03F3700EABBE9 /* MockBLEPeripheralBuilder.swift in Sources */,
39DE681125A03F3700EABBE9 /* MockBLEPeripheralProvider.swift in Sources */,
39DE681925A049FD00EABBE9 /* MockCBCentralManagerWrapper.swift in Sources */,
39AC6401245D18460024D677 /* BLEServiceTests.swift in Sources */,
397EC81C248202DB00225661 /* BLEDataTests.swift in Sources */,
Expand Down
31 changes: 9 additions & 22 deletions Source/Central/BLECentralManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,11 @@ public protocol BLECentralManager: AnyObject {
final class StandardBLECentralManager: BLECentralManager {

let centralManager: CBCentralManagerWrapper
let peripheralBuilder: BLEPeripheralBuilder
let peripheralProvider: BLEPeripheralProvider

var state = CurrentValueSubject<ManagerState, Never>(ManagerState.unknown)
let delegate: BLECentralManagerDelegate

private var scannedPeripherals = [UUID: BLEPeripheral]()
private var cancellables = [AnyCancellable]()

var isScanning: Bool {
Expand All @@ -43,11 +42,11 @@ final class StandardBLECentralManager: BLECentralManager {
init(
centralManager: CBCentralManagerWrapper,
managerDelegate: BLECentralManagerDelegate = BLECentralManagerDelegate(),
peripheralBuilder: BLEPeripheralBuilder = StandardBLEPeripheralBuilder()
peripheralProvider: BLEPeripheralProvider = StandardBLEPeripheralProvider()
) {
self.centralManager = centralManager
self.delegate = managerDelegate
self.peripheralBuilder = peripheralBuilder
self.peripheralProvider = peripheralProvider

if let centralManager = centralManager as? StandardCBCentralManagerWrapper {
centralManager.setupDelegate(managerDelegate)
Expand All @@ -73,9 +72,7 @@ final class StandardBLECentralManager: BLECentralManager {
.didConnectPeripheral
.sink { [weak self] result in
guard let self = self else { return }
if let scannedPeripheral = self.scannedPeripherals[result.identifier] as? BLEPeripheralState {
scannedPeripheral.connectionState.send(true)
}
self.peripheralProvider.provide(for: result, centralManager: self).connectionState.send(true)
}.store(in: &cancellables)
}

Expand All @@ -84,9 +81,7 @@ final class StandardBLECentralManager: BLECentralManager {
.didDisconnectPeripheral
.sink { [weak self] result in
guard let self = self else { return }
if let scannedPeripheral = self.scannedPeripherals[result.identifier] as? BLEPeripheralState {
scannedPeripheral.connectionState.send(false)
}
self.peripheralProvider.provide(for: result, centralManager: self).connectionState.send(false)
}.store(in: &cancellables)
}

Expand All @@ -106,17 +101,9 @@ final class StandardBLECentralManager: BLECentralManager {

return self.delegate
.didDiscoverAdvertisementData
.compactMap { [weak self] peripheral, advertisementData, rssi -> (BLEPeripheral, [String: Any], NSNumber)? in
guard let self = self, let blePeripheral = self.peripheralBuilder.build(
from: peripheral,
centralManager: self
) else { return nil }
return (blePeripheral, advertisementData, rssi)
}
.tryMap { [weak self] peripheral, advertisementData, rssi in
guard let self = self else { throw BLEError.deallocated }

self.scannedPeripherals[peripheral.peripheral.identifier] = peripheral
let peripheral = self.peripheralProvider.provide(for: peripheral, centralManager: self)

return BLEScanResult(
peripheral: peripheral,
Expand Down Expand Up @@ -158,7 +145,7 @@ final class StandardBLECentralManager: BLECentralManager {
delegate.didUpdateANCSAuthorization
.compactMap { [weak self] peripheral in
guard let self = self else { return nil }
return self.peripheralBuilder.build(from: peripheral, centralManager: self)
return self.peripheralProvider.provide(for: peripheral, centralManager: self)
}.eraseToAnyPublisher()
}

Expand All @@ -174,8 +161,8 @@ final class StandardBLECentralManager: BLECentralManager {
let peripherals = retrievedPeripherals
.compactMap { [weak self] peripheral -> BLEPeripheral? in
guard let self = self else { return nil }
return self.peripheralBuilder.build(
from: peripheral,
return self.peripheralProvider.provide(
for: peripheral,
centralManager: self
)
}
Expand Down
8 changes: 2 additions & 6 deletions Source/Central/CBCentralManagerWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,11 @@ final class StandardCBCentralManagerWrapper: CBCentralManagerWrapper {
}

func connect(_ peripheral: CBPeripheralWrapper, options: [String : Any]?) {
if let peripheral = peripheral as? StandardCBPeripheralWrapper, let realPeripheral = peripheral.peripheral {
wrappedManager.connect(realPeripheral, options: options)
}
wrappedManager.connect(peripheral.peripheral, options: options)
}

func cancelPeripheralConnection(_ peripheral: CBPeripheralWrapper) {
if let peripheral = peripheral as? StandardCBPeripheralWrapper, let realPeripheral = peripheral.peripheral {
wrappedManager.cancelPeripheralConnection(realPeripheral)
}
wrappedManager.cancelPeripheralConnection(peripheral.peripheral)
}

func registerForConnectionEvents(options: [CBConnectionEventMatchingOption : Any]?) {
Expand Down
2 changes: 1 addition & 1 deletion Source/Peripheral/BLEPeripheral.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ public protocol BLEPeripheral {
func writeValue(_ data: Data, for characteristic: CBCharacteristic, type: CBCharacteristicWriteType) -> AnyPublisher<Bool, BLEError>
}

protocol BLEPeripheralState {
protocol BLETrackedPeripheral: BLEPeripheral {
var connectionState: CurrentValueSubject<Bool, Never> { get }
}
34 changes: 0 additions & 34 deletions Source/Peripheral/BLEPeripheralBuilder.swift

This file was deleted.

53 changes: 53 additions & 0 deletions Source/Peripheral/BLEPeripheralProvider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//
// BLEPeripheralProvider.swift
// BLECombineKit
//
// Created by Henry Javier Serrano Echeverria on 2/1/21.
// Copyright © 2021 Henry Serrano. All rights reserved.
//

import Foundation

protocol BLEPeripheralProvider {
func provide(
for peripheral: CBPeripheralWrapper,
centralManager: BLECentralManager
) -> BLETrackedPeripheral
}

final class StandardBLEPeripheralProvider: BLEPeripheralProvider {

private lazy var queue = DispatchQueue(
label: String(describing: StandardBLEPeripheral.self),
attributes: .concurrent
)

private var peripherals = [UUID: BLETrackedPeripheral]()

func provide(
for peripheral: CBPeripheralWrapper,
centralManager: BLECentralManager
) -> BLETrackedPeripheral {
return existingPeripheral(id: peripheral.identifier) ?? {
let peripheralWrapper = StandardCBPeripheralWrapper(peripheral: peripheral.peripheral)
let peripheralDelegate = BLEPeripheralDelegate()
peripheralWrapper.setupDelegate(peripheralDelegate)

let blePeripheral = StandardBLEPeripheral(
peripheral: peripheralWrapper,
centralManager: centralManager,
delegate: peripheralDelegate
)
queue.async(flags: .barrier) { [weak self] in
self?.peripherals[peripheral.identifier] = blePeripheral
}
return blePeripheral
}()
}

private func existingPeripheral(id: UUID) -> BLETrackedPeripheral? {
queue.sync {
peripherals[id]
}
}
}
4 changes: 2 additions & 2 deletions Source/Peripheral/CBPeripheralWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Foundation
import CoreBluetooth

public protocol CBPeripheralWrapper {
var peripheral: CBPeripheral? { get }
var peripheral: CBPeripheral { get }
var state: CBPeripheralState { get }
var identifier: UUID { get }
var name: String? { get }
Expand All @@ -32,7 +32,7 @@ public protocol CBPeripheralWrapper {

final class StandardCBPeripheralWrapper: CBPeripheralWrapper {

var peripheral: CBPeripheral? {
var peripheral: CBPeripheral {
self.wrappedPeripheral
}

Expand Down
2 changes: 1 addition & 1 deletion Source/Peripheral/StandardBLEPeripheral.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import Combine
import CoreBluetooth

final public class StandardBLEPeripheral: BLEPeripheral, BLEPeripheralState {
final public class StandardBLEPeripheral: BLETrackedPeripheral {

let connectionState = CurrentValueSubject<Bool, Never>(false)
public let peripheral: CBPeripheralWrapper
Expand Down
22 changes: 11 additions & 11 deletions Tests/BLECentralManagerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,25 @@ class BLECentralManagerTests: XCTestCase {
var sut: BLECentralManager!
var delegate: BLECentralManagerDelegate!
var centralManagerWrapper: MockCBCentralManagerWrapper!
var peripheralBuilder: MockBLEPeripheralBuilder!
var peripheralProvider: MockBLEPeripheralProvider!
var cancellables = Set<AnyCancellable>()

override func setUpWithError() throws {
delegate = BLECentralManagerDelegate()
centralManagerWrapper = MockCBCentralManagerWrapper()
peripheralBuilder = MockBLEPeripheralBuilder()
peripheralProvider = MockBLEPeripheralProvider()

sut = StandardBLECentralManager(
centralManager: centralManagerWrapper,
managerDelegate: delegate,
peripheralBuilder: peripheralBuilder
peripheralProvider: peripheralProvider
)
}

override func tearDownWithError() throws {
delegate = nil
centralManagerWrapper = nil
peripheralBuilder = nil
peripheralProvider = nil
sut = nil
}

Expand All @@ -44,7 +44,7 @@ class BLECentralManagerTests: XCTestCase {
let peripheralMock = MockCBPeripheralWrapper()
var expectedScanResult: BLEScanResult?
let mockedPeripheral = MockBLEPeripheral()
peripheralBuilder.blePeripheral = mockedPeripheral
peripheralProvider.blePeripheral = mockedPeripheral

// When
sut.scanForPeripherals(withServices: [], options: nil)
Expand All @@ -69,13 +69,13 @@ class BLECentralManagerTests: XCTestCase {
sut = StandardBLECentralManager(
centralManager: centralManagerWrapper,
managerDelegate: delegate,
peripheralBuilder: arrayPeripheralBuilder
peripheralProvider: arrayPeripheralBuilder
)
let expectation = XCTestExpectation(description: self.debugDescription)
let peripheralMock = MockCBPeripheralWrapper()
let mockedPeripheral = MockBLEPeripheral()
var scanCounter = 0
arrayPeripheralBuilder.blePeripherals = [mockedPeripheral, nil, mockedPeripheral]
arrayPeripheralBuilder.blePeripherals = [mockedPeripheral, mockedPeripheral, mockedPeripheral]

// When
sut.scanForPeripherals(withServices: [], options: nil)
Expand Down Expand Up @@ -154,7 +154,7 @@ class BLECentralManagerTests: XCTestCase {
wait(for: [peripheralExpectation], timeout: 0.005)
XCTAssertNil(retrievedPeripheral) // BLEPeripheralBuilder is returning nil, so no peripherals returned
XCTAssertEqual(centralManagerWrapper.retrievePeripheralsWasCalledCount, 1)
XCTAssertEqual(peripheralBuilder.buildBLEPeripheralWasCalledCount, 1)
XCTAssertEqual(peripheralProvider.buildBLEPeripheralWasCalledCount, 0)
}

func testRetrieveConnectedPeripheralsReturns() throws {
Expand All @@ -175,7 +175,7 @@ class BLECentralManagerTests: XCTestCase {
wait(for: [peripheralExpectation], timeout: 0.005)
XCTAssertNil(retrievedPeripheral) // BLEPeripheralBuilder is returning nil, so no peripherals returned
XCTAssertEqual(centralManagerWrapper.retrieveConnectedPeripheralsWasCalledCount, 1)
XCTAssertEqual(peripheralBuilder.buildBLEPeripheralWasCalledCount, 1)
XCTAssertEqual(peripheralProvider.buildBLEPeripheralWasCalledCount, 0)
}

func testWillRestoreStateReturnsWhenDelegateUpdates() {
Expand Down Expand Up @@ -203,7 +203,7 @@ class BLECentralManagerTests: XCTestCase {
// Given
let observeDidUpdateANCSAuthorizationExpectation = expectation(description: "PeripheralExpectation")
let mockedCBPeripheralWrapper = MockCBPeripheralWrapper()
peripheralBuilder.blePeripheral = MockBLEPeripheral()
peripheralProvider.blePeripheral = MockBLEPeripheral()
var observedPeripheral: BLEPeripheral?

// When
Expand All @@ -219,7 +219,7 @@ class BLECentralManagerTests: XCTestCase {

// Then
wait(for: [observeDidUpdateANCSAuthorizationExpectation], timeout: 0.005)
XCTAssertEqual(peripheralBuilder.buildBLEPeripheralWasCalledCount, 1)
XCTAssertEqual(peripheralProvider.buildBLEPeripheralWasCalledCount, 1)
XCTAssertNotNil(observedPeripheral)
}

Expand Down
4 changes: 2 additions & 2 deletions Tests/BLEPeripheralTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,14 @@ class BLEPeripheralTests: XCTestCase {
func testConnectCallsCentralManagerToConnectPeripheralAndReturnsWhenConnectionStateIsTrue() throws {
// Given
let expectation = XCTestExpectation(description: #function)
var expectedPeripheral: BLEPeripheralState?
var expectedPeripheral: BLETrackedPeripheral?

// When
sut.connect(with: nil)
.sink(receiveCompletion: { completion in
expectation.fulfill()
}, receiveValue: { peripheral in
expectedPeripheral = peripheral as? BLEPeripheralState
expectedPeripheral = peripheral as? BLETrackedPeripheral
})
.store(in: &disposable)
sut.connectionState.send(true)
Expand Down
Loading