Skip to content

Commit 64547f4

Browse files
author
Paweł Janeczek
committedMay 18, 2018
- added all API for PeripheralManager
- added PeripheralManagerRestoredState - renamed RestoredState to CentralMangerRestoredState
1 parent bb870fb commit 64547f4

18 files changed

+541
-138
lines changed
 

‎.swiftlint.yml

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ excluded:
1515
- Carthage
1616
- ExampleApp
1717
- Tests
18+
- .build
1819

1920

2021
line_length:

‎RxBluetoothKit.xcodeproj/project.pbxproj

+16
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@
5050
0A7B28341F9F1B39003F950E /* BluetoothState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EF38C81D86EE1F00F9F468 /* BluetoothState.swift */; };
5151
0A7B28351F9F1C08003F950E /* RxBluetoothKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 2666FCEE1CCE42A5005E81CE /* RxBluetoothKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
5252
0A7B283D1F9F1C71003F950E /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0A7B28171F9F1B05003F950E /* RxSwift.framework */; };
53+
1D1B99D520AEB25C00464AD6 /* PeripheralManagerRestoredState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1B99D420AEB25C00464AD6 /* PeripheralManagerRestoredState.swift */; };
54+
1D1B99D720AEB27C00464AD6 /* CentralManagerRestoredState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1B99D620AEB27C00464AD6 /* CentralManagerRestoredState.swift */; };
55+
1D1B99DA20AEBE3200464AD6 /* _CentralManagerRestoredState.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1B99D820AEBE1800464AD6 /* _CentralManagerRestoredState.generated.swift */; };
56+
1D1B99DB20AEBE3300464AD6 /* _CentralManagerRestoredState.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1B99D820AEBE1800464AD6 /* _CentralManagerRestoredState.generated.swift */; };
57+
1D1B99DC20AEBE3400464AD6 /* _CentralManagerRestoredState.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1B99D820AEBE1800464AD6 /* _CentralManagerRestoredState.generated.swift */; };
5358
1D1C981C2019E8CF00DCF299 /* _CentralManager.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1C981A2019E8AE00DCF299 /* _CentralManager.generated.swift */; };
5459
1D1C981D2019E8D000DCF299 /* _CentralManager.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1C981A2019E8AE00DCF299 /* _CentralManager.generated.swift */; };
5560
1D1C981E2019E8D100DCF299 /* _CentralManager.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1C981A2019E8AE00DCF299 /* _CentralManager.generated.swift */; };
@@ -313,6 +318,9 @@
313318
0A7B28371F9F1C3C003F950E /* RxTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxTest.framework; path = Carthage/Build/tvOS/RxTest.framework; sourceTree = SOURCE_ROOT; };
314319
0A7B28381F9F1C3C003F950E /* Quick.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quick.framework; path = Carthage/Build/tvOS/Quick.framework; sourceTree = SOURCE_ROOT; };
315320
0A7B28391F9F1C3C003F950E /* Nimble.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nimble.framework; path = Carthage/Build/tvOS/Nimble.framework; sourceTree = SOURCE_ROOT; };
321+
1D1B99D420AEB25C00464AD6 /* PeripheralManagerRestoredState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeripheralManagerRestoredState.swift; sourceTree = "<group>"; };
322+
1D1B99D620AEB27C00464AD6 /* CentralManagerRestoredState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CentralManagerRestoredState.swift; sourceTree = "<group>"; };
323+
1D1B99D820AEBE1800464AD6 /* _CentralManagerRestoredState.generated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = _CentralManagerRestoredState.generated.swift; sourceTree = "<group>"; };
316324
1D1C981A2019E8AE00DCF299 /* _CentralManager.generated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = _CentralManager.generated.swift; sourceTree = "<group>"; };
317325
1D1C9827201B195000DCF299 /* CentralManager+RestoredState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CentralManager+RestoredState.swift"; sourceTree = "<group>"; };
318326
1D417F87200F436900354750 /* CentralManagerTest+ScanForPeripherals.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CentralManagerTest+ScanForPeripherals.swift"; sourceTree = "<group>"; };
@@ -509,6 +517,7 @@
509517
1D73E85520A434B0009167AA /* PeripheralManager+RestoredState.swift */,
510518
1DA3453C20A0819400F7D629 /* CBPeripheralManagerDelegateWrapper.swift */,
511519
1D73E83720A3289B009167AA /* StartAdvertisingResult.swift */,
520+
1D1B99D420AEB25C00464AD6 /* PeripheralManagerRestoredState.swift */,
512521
);
513522
name = PeripheralManager;
514523
sourceTree = "<group>";
@@ -533,6 +542,7 @@
533542
1D8116C61FFE0EE500147BF5 /* Autogenerated */ = {
534543
isa = PBXGroup;
535544
children = (
545+
1D1B99D820AEBE1800464AD6 /* _CentralManagerRestoredState.generated.swift */,
536546
1D73E83C20A32C98009167AA /* _PeripheralManager.generated.swift */,
537547
1D6E36CC20A07745009900A6 /* _ManagerType.generated.swift */,
538548
4C77E49920613B1800FAF1A9 /* _CentralManager+RestoredState.generated.swift */,
@@ -596,6 +606,7 @@
596606
1D9C50AE2021CC70006B21E4 /* Connector.swift */,
597607
A1299C0C1CBE3DEE005DEA5B /* AdvertisementData.swift */,
598608
26F3034A1CF0D49D00D74EBF /* RestoredState.swift */,
609+
1D1B99D620AEB27C00464AD6 /* CentralManagerRestoredState.swift */,
599610
BB2FF3341F9EAF2B00A12E10 /* CBCentralManagerDelegateWrapper.swift */,
600611
);
601612
name = CentralManager;
@@ -1238,6 +1249,7 @@
12381249
isa = PBXSourcesBuildPhase;
12391250
buildActionMask = 2147483647;
12401251
files = (
1252+
1D1B99DC20AEBE3400464AD6 /* _CentralManagerRestoredState.generated.swift in Sources */,
12411253
1D6E36D320A0784A009900A6 /* _ManagerType.generated.swift in Sources */,
12421254
4CB5044820457A2400031AA7 /* PeripheralTest+DescriptorsDiscover.swift in Sources */,
12431255
4CB5044D204582D700031AA7 /* PeripheralTest+DescriptorsOperation.swift in Sources */,
@@ -1301,6 +1313,7 @@
13011313
2666FE381CCE4732005E81CE /* Peripheral+Convenience.swift in Sources */,
13021314
2666FE3A1CCE4732005E81CE /* Service.swift in Sources */,
13031315
2666FE451CCE4732005E81CE /* BluetoothError.swift in Sources */,
1316+
1D1B99D720AEB27C00464AD6 /* CentralManagerRestoredState.swift in Sources */,
13041317
1DA3453D20A0819400F7D629 /* CBPeripheralManagerDelegateWrapper.swift in Sources */,
13051318
FA947A3B1EB1C41C000ED0B1 /* UUIDIdentifiable.swift in Sources */,
13061319
1DC4233F20078315009994B1 /* CBPeripheral+Uuid.swift in Sources */,
@@ -1315,6 +1328,7 @@
13151328
26F3034B1CF0D49D00D74EBF /* RestoredState.swift in Sources */,
13161329
37B64DBDA4A3B78934028507 /* PeripheralProvider.swift in Sources */,
13171330
1D9C509B202064CC006B21E4 /* Array+Utils.swift in Sources */,
1331+
1D1B99D520AEB25C00464AD6 /* PeripheralManagerRestoredState.swift in Sources */,
13181332
);
13191333
runOnlyForDeploymentPostprocessing = 0;
13201334
};
@@ -1324,6 +1338,7 @@
13241338
files = (
13251339
1D8116C81FFE0F1700147BF5 /* Mock.generated.swift in Sources */,
13261340
4CB5044620457A2200031AA7 /* PeripheralTest+DescriptorsDiscover.swift in Sources */,
1341+
1D1B99DA20AEBE3200464AD6 /* _CentralManagerRestoredState.generated.swift in Sources */,
13271342
4CB5044B204582D500031AA7 /* PeripheralTest+DescriptorsOperation.swift in Sources */,
13281343
1D490B581FFF8E1000D3F871 /* _Descriptor.generated.swift in Sources */,
13291344
4C77E49B20613B5400FAF1A9 /* _CentralManager+RestoredState.generated.swift in Sources */,
@@ -1405,6 +1420,7 @@
14051420
isa = PBXSourcesBuildPhase;
14061421
buildActionMask = 2147483647;
14071422
files = (
1423+
1D1B99DB20AEBE3300464AD6 /* _CentralManagerRestoredState.generated.swift in Sources */,
14081424
1D6E36D220A07849009900A6 /* _ManagerType.generated.swift in Sources */,
14091425
1D8116C91FFE0F1700147BF5 /* Mock.generated.swift in Sources */,
14101426
4CB5044720457A2300031AA7 /* PeripheralTest+DescriptorsDiscover.swift in Sources */,

‎Source/BluetoothError.swift

+8
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public enum BluetoothError: Error {
2828
// Services
2929
case servicesDiscoveryFailed(Peripheral, Error?)
3030
case includedServicesDiscoveryFailed(Peripheral, Error?)
31+
case addingServiceFailed(CBService, Error?)
3132
// Characteristics
3233
case characteristicsDiscoveryFailed(Service, Error?)
3334
case characteristicWriteFailed(Characteristic, Error?)
@@ -40,6 +41,7 @@ public enum BluetoothError: Error {
4041
case descriptorReadFailed(Descriptor, Error?)
4142
// L2CAP
4243
case openingL2CAPChannelFailed(Peripheral, Error?)
44+
case publishingL2CAPChanngelFailed(CBL2CAPPSM, Error?)
4345
}
4446

4547
extension BluetoothError: CustomStringConvertible {
@@ -92,6 +94,8 @@ extension BluetoothError: CustomStringConvertible {
9294
return "Services discovery error has occured: \(err?.localizedDescription ?? "-")"
9395
case let .includedServicesDiscoveryFailed(_, err):
9496
return "Included services discovery error has occured: \(err?.localizedDescription ?? "-")"
97+
case let .addingServiceFailed(_, err):
98+
return "Adding PeripheralManager service error has occured: \(err?.localizedDescription ?? "-")"
9599
// Characteristics
96100
case let .characteristicsDiscoveryFailed(_, err):
97101
return "Characteristics discovery error has occured: \(err?.localizedDescription ?? "-")"
@@ -112,6 +116,8 @@ extension BluetoothError: CustomStringConvertible {
112116
return "Descriptor read error has occured: \(err?.localizedDescription ?? "-")"
113117
case let .openingL2CAPChannelFailed(_, err):
114118
return "Opening L2CAP channel error has occured: \(err?.localizedDescription ?? "-")"
119+
case let .publishingL2CAPChanngelFailed(_, err):
120+
return "Publishing L2CAP channgel error has occured: \(err?.localizedDescription ?? "-")"
115121
}
116122
}
117123
}
@@ -153,6 +159,7 @@ public func == (lhs: BluetoothError, rhs: BluetoothError) -> Bool {
153159
// Services
154160
case let (.servicesDiscoveryFailed(l, _), .servicesDiscoveryFailed(r, _)): return l == r
155161
case let (.includedServicesDiscoveryFailed(l, _), .includedServicesDiscoveryFailed(r, _)): return l == r
162+
case let (.addingServiceFailed(l, _), .addingServiceFailed(r, _)): return l == r
156163
// Peripherals
157164
case let (.peripheralIsAlreadyObservingConnection(l), .peripheralIsAlreadyObservingConnection(r)): return l == r
158165
case let (.peripheralIsConnectingOrAlreadyConnected(l), .peripheralIsConnectingOrAlreadyConnected(r)): return l == r
@@ -173,6 +180,7 @@ public func == (lhs: BluetoothError, rhs: BluetoothError) -> Bool {
173180
case let (.descriptorReadFailed(l, _), .descriptorReadFailed(r, _)): return l == r
174181
// L2CAP
175182
case let (.openingL2CAPChannelFailed(l, _), .openingL2CAPChannelFailed(r, _)): return l == r
183+
case let (.publishingL2CAPChanngelFailed(l, _), .publishingL2CAPChanngelFailed(r, _)): return l == r
176184
default: return false
177185
}
178186
}

‎Source/CentralManager+RestoredState.swift

+37-16
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,45 @@ import Foundation
22
import RxSwift
33
import CoreBluetooth
44

5-
/// Closure that receives `RestoredState` as a parameter
5+
@available(*, deprecated: 5.1.0, renamed: "OnWillRestoreCentralManagerState")
66
public typealias OnWillRestoreState = (RestoredState) -> Void
7+
/// Closure that receives `RestoredState` as a parameter
8+
public typealias OnWillRestoreCentralManagerState = (CentralManagerRestoredState) -> Void
79

810
extension CentralManager {
911

1012
// MARK: State restoration
1113

14+
/// Deprecated, use CentralManager.init(queue:options:onWillRestoreCentralManagerState:) instead
15+
@available(*, deprecated: 5.1.0, renamed: "CentralManager.init(queue:options:onWillRestoreCentralManagerState:)")
16+
public convenience init(queue: DispatchQueue = .main,
17+
options: [String: AnyObject]? = nil,
18+
onWillRestoreState: OnWillRestoreState? = nil) {
19+
self.init(queue: queue, options: options)
20+
if let onWillRestoreState = onWillRestoreState {
21+
listenOnWillRestoreState(onWillRestoreState)
22+
}
23+
}
24+
1225
/// Creates new `CentralManager` instance, which supports bluetooth state restoration.
1326
/// - warning: If you pass background queue to the method make sure to observe results on main thread
1427
/// for UI related code.
1528
/// - parameter queue: Queue on which bluetooth callbacks are received. By default main thread is used
1629
/// and all operations and events are executed and received on main thread.
1730
/// - parameter options: An optional dictionary containing initialization options for a central manager.
1831
/// For more info about it please refer to [Central Manager initialization options](https://developer.apple.com/library/ios/documentation/CoreBluetooth/Reference/CBCentralManager_Class/index.html)
19-
/// - parameter onWillRestoreState: Closure called when state has been restored.
32+
/// - parameter onWillRestoreCentralManagerState: Closure called when state has been restored.
2033
///
21-
/// - seealso: `RestoredState`
34+
/// - seealso: `OnWillRestoreCentralManagerState`
2235
public convenience init(queue: DispatchQueue = .main,
2336
options: [String: AnyObject]? = nil,
24-
onWillRestoreState: OnWillRestoreState? = nil) {
37+
onWillRestoreCentralManagerState: OnWillRestoreCentralManagerState? = nil) {
2538
self.init(queue: queue, options: options)
26-
if let onWillRestoreState = onWillRestoreState {
27-
listenOnWillRestoreState(onWillRestoreState)
39+
if let onWillRestoreCentralManagerState = onWillRestoreCentralManagerState {
40+
listenOnWillRestoreState(onWillRestoreCentralManagerState)
2841
}
2942
}
3043

31-
// swiftlint:enable line_length
32-
3344
/// Creates new `CentralManager`
3445
/// - parameter centralManager: Central instance which is used to perform all of the necessary operations
3546
/// - parameter delegateWrapper: Wrapper on CoreBluetooth's central manager callbacks.
@@ -41,28 +52,38 @@ extension CentralManager {
4152
delegateWrapper: CBCentralManagerDelegateWrapper,
4253
peripheralProvider: PeripheralProvider,
4354
connector: Connector,
44-
onWillRestoreState: @escaping OnWillRestoreState
45-
) {
55+
onWillRestoreCentralManagerState: @escaping OnWillRestoreCentralManagerState
56+
) {
4657
self.init(
4758
centralManager: centralManager,
4859
delegateWrapper: delegateWrapper,
4960
peripheralProvider: peripheralProvider,
5061
connector: connector
5162
)
52-
listenOnWillRestoreState(onWillRestoreState)
63+
listenOnWillRestoreState(onWillRestoreCentralManagerState)
64+
}
65+
66+
func listenOnWillRestoreState(_ handler: @escaping OnWillRestoreState) {
67+
_ = restoreStateObservable
68+
.map { RestoredState(centralManagerRestoredState: $0) }
69+
.subscribe(onNext: { handler($0) })
5370
}
5471

5572
/// Emits `RestoredState` instance, when state of `CentralManager` has been restored,
5673
/// Should only be called once in the lifetime of the app
5774
/// - returns: Observable which emits next events state has been restored
58-
func listenOnWillRestoreState(_ handler: @escaping OnWillRestoreState) {
59-
_ = delegateWrapper
75+
func listenOnWillRestoreState(_ handler: @escaping OnWillRestoreCentralManagerState) {
76+
_ = restoreStateObservable
77+
.subscribe(onNext: { handler($0) })
78+
}
79+
80+
var restoreStateObservable: Observable<CentralManagerRestoredState> {
81+
return delegateWrapper
6082
.willRestoreState
6183
.take(1)
62-
.flatMap { [weak self] dict -> Observable<RestoredState> in
84+
.flatMap { [weak self] dict -> Observable<CentralManagerRestoredState> in
6385
guard let strongSelf = self else { throw BluetoothError.destroyed }
64-
return .just(RestoredState(restoredStateDictionary: dict, centralManager: strongSelf))
86+
return .just(CentralManagerRestoredState(restoredStateDictionary: dict, centralManager: strongSelf))
6587
}
66-
.subscribe(onNext: { handler($0) })
6788
}
6889
}

‎Source/CentralManager.swift

-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ public class CentralManager: ManagerType {
2525
/// Implementation of CBCentralManager
2626
public let manager: CBCentralManager
2727

28-
/// Implementation of CBCentralManager
2928
@available(*, deprecated: 5.1.0, renamed: "CentralManager.manager")
3029
public var centralManager: CBCentralManager { return manager }
3130

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import Foundation
2+
import CoreBluetooth
3+
4+
/// It should be deleted when `RestoredState` will be deleted
5+
protocol CentralManagerRestoredStateType {
6+
var restoredStateData: [String: Any] { get }
7+
var centralManager: CentralManager { get }
8+
var peripherals: [Peripheral] { get }
9+
var scanOptions: [String: AnyObject]? { get }
10+
var services: [Service] { get }
11+
}
12+
13+
/// Convenience class which helps reading state of restored CentralManager.
14+
public struct CentralManagerRestoredState: CentralManagerRestoredStateType {
15+
16+
/// Restored state dictionary.
17+
public let restoredStateData: [String: Any]
18+
19+
public unowned let centralManager: CentralManager
20+
/// Creates restored state information based on CoreBluetooth's dictionary
21+
/// - parameter restoredStateDictionary: Core Bluetooth's restored state data
22+
/// - parameter centralManager: `CentralManager` instance of which state has been restored.
23+
init(restoredStateDictionary: [String: Any], centralManager: CentralManager) {
24+
restoredStateData = restoredStateDictionary
25+
self.centralManager = centralManager
26+
}
27+
28+
/// Array of `Peripheral` objects which have been restored.
29+
/// These are peripherals that were connected to the central manager (or had a connection pending)
30+
/// at the time the app was terminated by the system.
31+
public var peripherals: [Peripheral] {
32+
let objects = restoredStateData[CBCentralManagerRestoredStatePeripheralsKey] as? [AnyObject]
33+
guard let arrayOfAnyObjects = objects else { return [] }
34+
35+
#if swift(>=4.1)
36+
let cbPeripherals = arrayOfAnyObjects.compactMap { $0 as? CBPeripheral }
37+
#else
38+
let cbPeripherals = arrayOfAnyObjects.flatMap { $0 as? CBPeripheral }
39+
#endif
40+
41+
return cbPeripherals.map { centralManager.retrievePeripheral(for: $0) }
42+
}
43+
44+
/// Dictionary that contains all of the peripheral scan options that were being used
45+
/// by the central manager at the time the app was terminated by the system.
46+
public var scanOptions: [String: AnyObject]? {
47+
return restoredStateData[CBCentralManagerRestoredStatePeripheralsKey] as? [String: AnyObject]
48+
}
49+
50+
/// Array of `Service` objects which have been restored.
51+
/// These are all the services the central manager was scanning for at the time the app
52+
/// was terminated by the system.
53+
public var services: [Service] {
54+
let objects = restoredStateData[CBCentralManagerRestoredStateScanServicesKey] as? [AnyObject]
55+
guard let arrayOfAnyObjects = objects else { return [] }
56+
57+
#if swift(>=4.1)
58+
let cbServices = arrayOfAnyObjects.compactMap { $0 as? CBService }
59+
#else
60+
let cbServices = arrayOfAnyObjects.flatMap { $0 as? CBService }
61+
#endif
62+
63+
return cbServices.map { Service(peripheral: centralManager.retrievePeripheral(for: $0.peripheral),
64+
service: $0) }
65+
}
66+
}

0 commit comments

Comments
 (0)