A-A+

RxSwift 封装 CoreBluetooth(二) 扫描

2020年09月30日 iOS原创文章 暂无评论
博客主机

首先实现扫描功能,

1: 定义扫描接口,定义接口主要是降低耦合(实现该接口可以很轻松的重构扫描模块)

1:ScanBuilder 扫描构建器,描述创建扫描类需要的参数,以及返回对应的扫描器实例。
2:只有一个函数 scan ,返回值为 Observable
protocol BluetoothScanable {

    var scanInfo: (scanPrefix: [String], services: [CBUUID]) { get }
    var centralManager : CBCentralManager { get }

    typealias Input = (
        centralManager: CBCentralManager,
        scanInfo: (scanPrefix: [String], services: [CBUUID])
    )

    typealias ScanBuilder = (BluetoothScanable.Input) -> BluetoothScanable

    func scan(duration: Int) -> Observable<(state: ScanState, response : [ScanResponse]?)>

}

public class ScanResponse {

    var peripheral: CBPeripheral
    var advertisementData: [String : Any]?
    var rssi: NSNumber

    init(peripheral: CBPeripheral,
         advertisementData: [String : Any]? = nil,
         rssi: NSNumber = NSNumber.init(value: 0)) {
        self.peripheral = peripheral
        self.advertisementData = advertisementData
        self.rssi = rssi
    }
}

2: 扫描实现类

实现 BluetoothScanable 接口, 扫描的结果通过 信号的方式回传。

class BluetoothScan: BluetoothScanable {

    var scanInfo: (scanPrefix: [String], services: [CBUUID])
    var centralManager: CBCentralManager

    init(centralManager: CBCentralManager, scanInfo: (scanPrefix: [String], services: [CBUUID])) {
        self.centralManager = centralManager
        self.scanInfo = scanInfo
    }

    func scan(duration: Int) -> Observable<(state: ScanState, response : [ScanResponse]?)> {
        // 返回 Observable
        return Observable<(state: ScanState, response : [ScanResponse]?)>.create { [centralManager, scanInfo] (subscriber) -> Disposable in
            if centralManager.state == .poweredOn {
                // 获取已连接
                var connected = centralManager.retrieveConnectedPeripherals(withServices: scanInfo.services)
                // 扫描前缀过滤
                connected = connected.filter({ p in
                    return (scanInfo.scanPrefix.filter({(p.name?.hasPrefix($0) ?? false)}).count) > 0
                })
                // 转为 ScanResponse 对象
                let scanResponses = connected.map({ ScanResponse(peripheral: $0) })
                if scanResponses.count > 0 {
                    subscriber.onNext((state: .nomal, response: scanResponses))
                }

                // 订阅扫描结果 ,接收信号发送过来的扫描结果
                _ = centralManager.rx.didDiscoverPeripheral.filter({ p in
                    return (scanInfo.scanPrefix.filter({
                        (p.peripheral.name?.hasPrefix($0) ?? false)
                     }).count) > 0
                }).subscribe(onNext: { (response) in
                 //信号发送给订阅者
                    subscriber.onNext((state: .nomal, response: [response]))
                })

                // 开始扫描
                if UIApplication.shared.applicationState == .background {
                    centralManager.scanForPeripherals(withServices: scanInfo.services , options: nil)
                } else {
                    centralManager.scanForPeripherals(withServices: nil, options: nil)
                }

                // 指定时间停止扫描
                DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(duration)) {
                   //结束发送给订阅者
                    centralManager.stopScan()
                    subscriber.onNext((state: .end, response: []))
                    subscriber.onCompleted()
                }
            } else {
                subscriber.onError(ScanError.error(messae: "Bluetooth state error"))
            }
            return Disposables.create()
        }
    }
}

3 : 扫描结果订阅的实现

CBCentralManager 扩展rx属性 , 直接返回 RxCBCentralManagerDelegateProxy 对象中的PublishSubject 属性。 外部订阅 rx 属性即可收到扫描结果信号。

extension Reactive where Base: CBCentralManager {

    public var delegate: DelegateProxy<CBCentralManager, CBCentralManagerDelegate> {
        return RxCBCentralManagerDelegateProxy.proxy(for: base)
    }

    public var didUpdateState: Observable<CBManagerState> {
        return RxCBCentralManagerDelegateProxy.proxy(for: base)
            .didUpdateStateSubject
            .asObservable()
    }

    public var didDiscoverPeripheral: Observable<ScanResponse> {
        return RxCBCentralManagerDelegateProxy.proxy(for: base)
            .didDiscoverPeripheralSubject
            .asObservable()
    }

    public var didConectPeripheral: Observable<ScanResponse> {
        return RxCBCentralManagerDelegateProxy.proxy(for: base)
            .didConnectPeripheralSubject
            .asObservable()
    }

    public var didFailToConnectPeripheral: Observable<ScanResponse> {
        return RxCBCentralManagerDelegateProxy.proxy(for: base)
            .didFailToConnectPeripheralSubject
            .asObservable()
    }

    public var didDisconnectPeripheral: Observable<ScanResponse> {
        return RxCBCentralManagerDelegateProxy.proxy(for: base)
            .didDisconnectPeripheralSubject
            .asObservable()
    }

}

class RxCBCentralManagerDelegateProxy: DelegateProxy<CBCentralManager, CBCentralManagerDelegate>, DelegateProxyType, CBCentralManagerDelegate {

        // 系统代理会掉时,用于发送信号, 任何想知道扫描结果的都可以订阅
        var didUpdateStateSubject = PublishSubject<CBManagerState>()
        var didDiscoverPeripheralSubject = PublishSubject<ScanResponse>()
        var didConnectPeripheralSubject = PublishSubject<ScanResponse>()
        var didFailToConnectPeripheralSubject = PublishSubject<ScanResponse>()
        var didDisconnectPeripheralSubject = PublishSubject<ScanResponse>()

        init(_ centerManager: CBCentralManager) {
            super.init(parentObject: centerManager, delegateProxy: RxCBCentralManagerDelegateProxy.self)
        }

        /// 注册代理的实现为 RxCBCentralManagerDelegateProxy 实例
        static func registerKnownImplementations() {
            self.register {
                RxCBCentralManagerDelegateProxy($0)
            }
        }

        static func currentDelegate(for object: CBCentralManager) -> CBCentralManagerDelegate? {
            return object.delegate
        }

        static func setCurrentDelegate(_ delegate: CBCentralManagerDelegate?, to object: CBCentralManager) {
            object.delegate = delegate
        }

        func centralManagerDidUpdateState(_ central: CBCentralManager) {
            _forwardToDelegate?.centralManagerDidUpdateState(central)
            /// 当代理回调 蓝牙状态发生变化 发送信号给订阅者
            didUpdateStateSubject.onNext(central.state)
        }

        func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
            didDiscoverPeripheralSubject.onNext(ScanResponse(peripheral: peripheral, advertisementData: advertisementData, rssi: RSSI))
        }

        func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
            didConnectPeripheralSubject.onNext(ScanResponse(peripheral: peripheral))
        }

        func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
            didFailToConnectPeripheralSubject.onNext(ScanResponse(peripheral: peripheral))
        }

        func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
            didDisconnectPeripheralSubject.onNext(ScanResponse(peripheral: peripheral))
        }
    }

4 : 具体使用

1: 在 didFinishLaunchingWithOptions 中 先配置 BleFacade (初始化蓝牙)提供要连接的设备名或扫描的前缀以及服务特征,配置BleFacade 中使用的设备扫描器 和 设备连接器。 所有蓝牙操作都通过BleFacade类执行。

    // 连接 的具体实现类,  扫描器的Builer 会传入 centralManager 和 scanInfo
    let scanBuilder: BluetoothScanable.ScanBuilder = {
        BluetoothScan(centralManager: $0.centralManager, scanInfo: $0.scanInfo)
    }

            //  连接 的具体实现类,  扫描器的Builer 会传入 centralManager 和 scanInfo 以及 scaner
    let connectBuilder: BluetoothConnectable.ConnectBuilder = {
        BluetoothConnect(
            centralManager: $0.centralManager,
            connectInfo: $0.connectInfo,
            scaner: $0.scaner
        )
    }

    // 扫描 和 连接 的配置
    let services = [CBUUID.init(string: "service uuid1"), CBUUID.init(string: "service uuid2")]
    let config = BleDeviceConfig("DeviceName", ["DeviceNamePrefix"], services)
    BleFacade.shared.config(config, scanBuilder, connectBuilder)

// 在需要扫描的地方 执行扫描操作即可

func clicnScanBtn(_ sender: Any) {

        BleFacade.shared.scaner.scan(duration: 3)
            .subscribe(onNext: { (state, response) in
                if state == .nomal {
                    response?.filter({ $0.peripheral.name != nil }).forEach({ (res) in
                        print("per name: \(String(describing: res.peripheral.name))")
                    })
                } else if (state == .end) {
                    print("扫描结束")
                }
            }, onError: { error in
                    print("\(error)")
                }).disposed(by: bag)

    }

给我留言

Copyright © ios教程,苹果粉丝,苹果资讯,ios入门教程,ios学习,ios程序员,ios视频教程,ios粉丝网 保留所有权利.   Theme  Ality

用户登录