Skip to content

Commit f4a4147

Browse files
committed
Merge branch 'master' of https://github.com/Henryforce/BLECombineKit into pr/15
2 parents 3afba75 + 0afe23a commit f4a4147

13 files changed

Lines changed: 177 additions & 51 deletions

BLECombineKit.xcodeproj/project.pbxproj

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
archiveVersion = 1;
44
classes = {
55
};
6-
objectVersion = 50;
6+
objectVersion = 52;
77
objects = {
88

99
/* Begin PBXBuildFile section */
@@ -52,6 +52,7 @@
5252
39E7B702245ED60B0065044C /* DevicesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39E7B701245ED60B0065044C /* DevicesView.swift */; };
5353
39E7B705245ED6840065044C /* ActionState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39E7B704245ED6840065044C /* ActionState.swift */; };
5454
39E7B708245EDA320065044C /* BLECombineKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39E7B707245EDA320065044C /* BLECombineKit.swift */; };
55+
486C7B6226E90D3F0061CC52 /* CombineExt in Frameworks */ = {isa = PBXBuildFile; productRef = 486C7B6126E90D3F0061CC52 /* CombineExt */; };
5556
/* End PBXBuildFile section */
5657

5758
/* Begin PBXContainerItemProxy section */
@@ -145,6 +146,7 @@
145146
isa = PBXFrameworksBuildPhase;
146147
buildActionMask = 2147483647;
147148
files = (
149+
486C7B6226E90D3F0061CC52 /* CombineExt in Frameworks */,
148150
);
149151
runOnlyForDeploymentPostprocessing = 0;
150152
};
@@ -412,6 +414,9 @@
412414
dependencies = (
413415
);
414416
name = BLECombineKit;
417+
packageProductDependencies = (
418+
486C7B6126E90D3F0061CC52 /* CombineExt */,
419+
);
415420
productName = BLECombineKit;
416421
productReference = 39AC63C4245D07A70024D677 /* BLECombineKit.framework */;
417422
productType = "com.apple.product-type.framework";
@@ -484,6 +489,9 @@
484489
Base,
485490
);
486491
mainGroup = 39AC63BA245D07A70024D677;
492+
packageReferences = (
493+
486C7B6026E90D3F0061CC52 /* XCRemoteSwiftPackageReference "CombineExt" */,
494+
);
487495
productRefGroup = 39AC63C5245D07A70024D677 /* Products */;
488496
projectDirPath = "";
489497
projectRoot = "";
@@ -907,6 +915,25 @@
907915
defaultConfigurationName = Release;
908916
};
909917
/* End XCConfigurationList section */
918+
919+
/* Begin XCRemoteSwiftPackageReference section */
920+
486C7B6026E90D3F0061CC52 /* XCRemoteSwiftPackageReference "CombineExt" */ = {
921+
isa = XCRemoteSwiftPackageReference;
922+
repositoryURL = "https://github.com/CombineCommunity/CombineExt.git";
923+
requirement = {
924+
kind = upToNextMajorVersion;
925+
minimumVersion = 1.3.0;
926+
};
927+
};
928+
/* End XCRemoteSwiftPackageReference section */
929+
930+
/* Begin XCSwiftPackageProductDependency section */
931+
486C7B6126E90D3F0061CC52 /* CombineExt */ = {
932+
isa = XCSwiftPackageProductDependency;
933+
package = 486C7B6026E90D3F0061CC52 /* XCRemoteSwiftPackageReference "CombineExt" */;
934+
productName = CombineExt;
935+
};
936+
/* End XCSwiftPackageProductDependency section */
910937
};
911938
rootObject = 39AC63BB245D07A70024D677 /* Project object */;
912939
}

BLECombineKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

BLECombineKit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 34 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,16 @@ let package = Package(
1111
products: [
1212
.library(name: "BLECombineKit", targets: ["BLECombineKit"])
1313
],
14-
dependencies: [],
14+
dependencies: [
15+
.package(
16+
url: "https://github.com/CombineCommunity/CombineExt.git",
17+
from: "1.0.0"
18+
)
19+
],
1520
targets: [
1621
.target(
1722
name: "BLECombineKit",
18-
dependencies: [],
23+
dependencies: ["CombineExt"],
1924
path: ".",
2025
exclude: [
2126
"Source/BLECombineKit.h",

Source/Central/BLECentralManager.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import Foundation
1010
import CoreBluetooth
1111
import Combine
12+
import CombineExt
1213

1314
public protocol BLECentralManager: AnyObject {
1415
var centralManager: CBCentralManagerWrapper { get }
@@ -19,7 +20,7 @@ public protocol BLECentralManager: AnyObject {
1920
func scanForPeripherals(withServices services: [CBUUID]?, options: [String: Any]?) -> AnyPublisher<BLEScanResult, BLEError>
2021
func stopScan()
2122
func connect(peripheralWrapper: CBPeripheralWrapper, options: [String:Any]?)
22-
func cancelPeripheralConnection(_ peripheral: CBPeripheralWrapper) -> AnyPublisher<Bool, BLEError>
23+
func cancelPeripheralConnection(_ peripheral: CBPeripheralWrapper) -> AnyPublisher<Never, Never>
2324
func registerForConnectionEvents(options: [CBConnectionEventMatchingOption : Any]?)
2425
func observeWillRestoreState() -> AnyPublisher<[String: Any], Never>
2526
func observeDidUpdateANCSAuthorization() -> AnyPublisher<BLEPeripheral, Never>
@@ -123,13 +124,14 @@ final class StandardBLECentralManager: BLECentralManager {
123124
centralManager.connect(peripheralWrapper, options: options)
124125
}
125126

126-
public func cancelPeripheralConnection(_ peripheral: CBPeripheralWrapper) -> AnyPublisher<Bool, BLEError> {
127+
public func cancelPeripheralConnection(_ peripheral: CBPeripheralWrapper) -> AnyPublisher<Never, Never> {
127128
centralManager.cancelPeripheralConnection(peripheral)
128129

129130
return delegate.didDisconnectPeripheral
130131
.filter { $0.identifier == peripheral.identifier }
131-
.map { _ in true }
132-
.setFailureType(to: BLEError.self)
132+
.first()
133+
.ignoreOutput()
134+
.ignoreFailure()
133135
.eraseToAnyPublisher()
134136
}
135137

Source/Characteristic/BLECharacteristic.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,11 @@ public struct BLECharacteristic: BLEPeripheralResult {
3030
public func setNotifyValue(_ enabled: Bool) {
3131
peripheral.setNotifyValue(enabled, for: value)
3232
}
33+
34+
public func writeValue(
35+
_ data: Data,
36+
type: CBCharacteristicWriteType
37+
) -> AnyPublisher<Never, BLEError> {
38+
return peripheral.writeValue(data, for: self.value, type: type)
39+
}
3340
}

Source/Peripheral/BLEPeripheral.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,15 @@ public protocol BLEPeripheral {
1515

1616
func observeConnectionState() -> AnyPublisher<Bool, Never>
1717
func connect(with options: [String: Any]?) -> AnyPublisher<BLEPeripheral, BLEError>
18-
@discardableResult func disconnect() -> AnyPublisher<Bool, BLEError>
18+
@discardableResult func disconnect() -> AnyPublisher<Never, BLEError>
19+
func observeNameValue() -> AnyPublisher<String, Never>
1920
func observeRSSIValue() -> AnyPublisher<NSNumber, BLEError>
2021
func discoverServices(serviceUUIDs: [CBUUID]?) -> AnyPublisher<BLEService, BLEError>
2122
func discoverCharacteristics(characteristicUUIDs: [CBUUID]?, for service: CBService) -> AnyPublisher<BLECharacteristic, BLEError>
2223
func observeValue(for characteristic: CBCharacteristic) -> AnyPublisher<BLEData, BLEError>
2324
func observeValueUpdateAndSetNotification(for characteristic: CBCharacteristic) -> AnyPublisher<BLEData, BLEError>
2425
func setNotifyValue(_ enabled: Bool, for characteristic: CBCharacteristic)
25-
func writeValue(_ data: Data, for characteristic: CBCharacteristic, type: CBCharacteristicWriteType) -> AnyPublisher<Bool, BLEError>
26+
func writeValue(_ data: Data, for characteristic: CBCharacteristic, type: CBCharacteristicWriteType) -> AnyPublisher<Never, BLEError>
2627
}
2728

2829
protocol BLETrackedPeripheral: BLEPeripheral {

Source/Peripheral/BLEPeripheralDelegate.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import Foundation
1010
import CoreBluetooth
1111
import Combine
1212

13+
typealias DidUpdateName = (peripheral: CBPeripheralWrapper, name: String)
1314
typealias DidDiscoverServicesResult = (peripheral: CBPeripheralWrapper, error: Error?)
1415
typealias DidDiscoverCharacteristicsResult = (peripheral: CBPeripheralWrapper, service: CBService, error: Error?)
1516
typealias DidUpdateValueForCharacteristicResult = (peripheral: CBPeripheralWrapper, characteristic: CBCharacteristic, error: Error?)
@@ -20,6 +21,9 @@ typealias DidWriteValueForCharacteristicResult = (peripheral: CBPeripheralWrappe
2021

2122
final class BLEPeripheralDelegate: NSObject {
2223

24+
// name updated
25+
let didUpdateName = PassthroughSubject<DidUpdateName, Never>()
26+
2327
// Discovering Services
2428
let didDiscoverServices = PassthroughSubject<DidDiscoverServicesResult, Error>()
2529

@@ -40,6 +44,13 @@ final class BLEPeripheralDelegate: NSObject {
4044
}
4145

4246
extension BLEPeripheralDelegate: CBPeripheralDelegate {
47+
func peripheralDidUpdateName(_ peripheral: CBPeripheral) {
48+
let peripheralWrapper = StandardCBPeripheralWrapper(peripheral: peripheral)
49+
if let name = peripheral.name {
50+
didUpdateName.send((peripheral: peripheralWrapper, name: name))
51+
}
52+
}
53+
4354
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
4455
let peripheralWrapper = StandardCBPeripheralWrapper(peripheral: peripheral)
4556
didDiscoverServices.send((peripheral: peripheralWrapper, error: error))

Source/Peripheral/StandardBLEPeripheral.swift

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ final public class StandardBLEPeripheral: BLETrackedPeripheral {
1818
private var connectCancellable: AnyCancellable?
1919
private var discoverServicesCancellable: AnyCancellable?
2020
private var discoverCharacteristicsCancellable: AnyCancellable?
21-
private var writeValueCancellable: AnyCancellable?
2221

2322
init(
2423
peripheral: CBPeripheralWrapper,
@@ -67,14 +66,24 @@ final public class StandardBLEPeripheral: BLETrackedPeripheral {
6766
}
6867

6968
@discardableResult
70-
public func disconnect() -> AnyPublisher<Bool, BLEError> {
69+
public func disconnect() -> AnyPublisher<Never, BLEError> {
7170
guard let centralManager = centralManager else {
7271
return Just.init(false)
7372
.tryMap { _ in throw BLEError.disconnectionFailed }
7473
.mapError { $0 as? BLEError ?? BLEError.unknown }
7574
.eraseToAnyPublisher()
7675
}
77-
return centralManager.cancelPeripheralConnection(peripheral)
76+
return centralManager
77+
.cancelPeripheralConnection(peripheral)
78+
.setFailureType(to: BLEError.self)
79+
.eraseToAnyPublisher()
80+
}
81+
82+
public func observeNameValue() -> AnyPublisher<String, Never> {
83+
return delegate
84+
.didUpdateName
85+
.map({ $1 })
86+
.eraseToAnyPublisher()
7887
}
7988

8089
public func observeRSSIValue() -> AnyPublisher<NSNumber, BLEError> {
@@ -189,30 +198,30 @@ final public class StandardBLEPeripheral: BLETrackedPeripheral {
189198
_ data: Data,
190199
for characteristic: CBCharacteristic,
191200
type: CBCharacteristicWriteType
192-
) -> AnyPublisher<Bool, BLEError> {
193-
peripheral.writeValue(data, for: characteristic, type: type)
194-
writeValueCancellable?.cancel()
201+
) -> AnyPublisher<Never, BLEError> {
202+
defer {
203+
peripheral.writeValue(data, for: characteristic, type: type)
204+
}
195205

196206
switch type {
197207
case .withResponse:
198-
return Future<Bool, BLEError> { [weak self] promise in
199-
guard let self = self else { return }
200-
self.writeValueCancellable = self.delegate
201-
.didWriteValueForCharacteristic
202-
.tryMap { result -> Bool in
203-
if let error = result.error { throw BLEError.writeFailed(error) }
204-
return result.characteristic == characteristic
208+
return self.delegate
209+
.didWriteValueForCharacteristic
210+
.filter({ $0.characteristic == characteristic })
211+
.tryMap({ result -> CBCharacteristic in
212+
if let error = result.error {
213+
throw error
205214
}
206-
.mapError { $0 as? BLEError ?? BLEError.unknown }
207-
.sink(receiveCompletion: { completion in
208-
guard case .failure(let error) = completion else { return }
209-
promise(.failure(error))
210-
}, receiveValue: { value in
211-
promise(.success(value))
212-
})
213-
}.eraseToAnyPublisher()
215+
return result.characteristic
216+
})
217+
.mapError({ BLEError.writeFailed($0) })
218+
.first()
219+
.ignoreOutput()
220+
.eraseToAnyPublisher()
214221
default:
215-
return Just.init(true).setFailureType(to: BLEError.self).eraseToAnyPublisher()
222+
return Empty(completeImmediately: true)
223+
.setFailureType(to: BLEError.self)
224+
.eraseToAnyPublisher()
216225
}
217226
}
218227

Tests/BLECharacteristicTests.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,14 @@ class BLECharacteristicTests: XCTestCase {
4848

4949
XCTAssertTrue(blePeripheralMock.setNotifyValueWasCalled)
5050
}
51+
52+
func testWriteValue() {
53+
let cbCharacteristic = CBMutableCharacteristic(type: CBUUID.init(string: "0x0000"), properties: CBCharacteristicProperties.init(), value: Data(), permissions: CBAttributePermissions.init())
54+
let sut = BLECharacteristic(value: cbCharacteristic, peripheral: blePeripheralMock)
55+
56+
_ = sut.writeValue(Data(), type: .withResponse)
57+
58+
XCTAssertTrue(blePeripheralMock.writeValueWasCalled)
59+
}
5160

5261
}

0 commit comments

Comments
 (0)