123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372 |
- //
- // RDSBabyBluetooth.m
- // RuiZhi
- //
- // Created by Rayson on 2020/6/13.
- // Copyright © 2020 RDIOT. All rights reserved.
- //
- #import "RDSBabyBluetooth.h"
- #import "NSString+convert.h"
- #import "NSString+safe.h"
- #import "RDSDeallocWatcher.h"
- #import <objc/runtime.h>
- #define Server_00FF @"00FF"
- #define Characteristic_FF01 @"FF01"
- @interface RDSBabyBluetooth ()<CBCentralManagerDelegate,CBPeripheralDelegate>
- @property (nonatomic, copy) NSString *deviceName;// 要连接的设备名
- @property (nonatomic, strong) CBCentralManager *centralManager;
- @property (nonatomic,strong) CBCharacteristic *characteristic;
- @property (nonatomic,strong) CBPeripheral *peripheral;
- @property (nonatomic, strong) NSMapTable *blockTable;
- @property (nonatomic, strong) NSMapTable *blockTableDisconnect;
- @property (nonatomic, assign) BOOL isBinding;
- @end
- @implementation RDSBabyBluetooth
- //DEF_SINGLETON(RDSBabyBluetooth)
- // 初始化单例方法
- + (instancetype)sharedInstance
- {
- static RDSBabyBluetooth *manager = nil;
- static dispatch_once_t oneToken;
-
- // dispatch_once 是线程安全的,能够做到在多线程的环境下Block中的代码只会被执行一次
- dispatch_once(&oneToken, ^{
- manager = [[RDSBabyBluetooth alloc] init];
- [manager p_setup];
- });
- return manager;
- }
- // 初始化
- - (void)p_setup{
-
- //初始化 蓝牙库
- dispatch_queue_t queue = dispatch_queue_create("yxlj.com", DISPATCH_QUEUE_SERIAL);
- _centralManager = [[CBCentralManager alloc]initWithDelegate:self queue:queue options:@{@"CBCentralManagerOptionShowPowerAlertKey":@YES}];
-
-
- // 创建 NSMapTable 映射表
- self.blockTable = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsWeakMemory valueOptions:NSPointerFunctionsStrongMemory capacity:1];
- self.blockTableDisconnect = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsWeakMemory valueOptions:NSPointerFunctionsStrongMemory capacity:1];
-
- }
- - (void)rds_beginScan{
-
- if(_centralManager == nil){
- dispatch_queue_t queue = dispatch_queue_create("yxlj.com", DISPATCH_QUEUE_SERIAL);
- _centralManager = [[CBCentralManager alloc]initWithDelegate:self queue:queue options:@{@"CBCentralManagerOptionShowPowerAlertKey":@YES}];
- }
- else{
- [_centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:Server_00FF]] options:nil];
- }
- }
- - (void)rds_cancelScan{
- //停止扫描
- [self.centralManager stopScan];
- }
- - (void)rds_cancelConnection{
- //停止之前的连接
- if(self.centralManager && self.peripheral){
- [self.centralManager cancelPeripheralConnection:self.peripheral];
- }
-
- _isBinding = NO;
- }
- - (void)rds_refreshScanDeviceName:(NSString *)name{
-
- _isBinding = YES;
- self.deviceName = name;
- [self rds_refreshScan];
- }
- - (void)rds_refreshScan{
-
- DDLog(@"重新扫描设备");
- [self rds_beginScan];
-
- }
- #pragma mark - 写一个值
- //写一个值
- -(void)rds_writeValue:(NSData *)data{
-
- if (data == nil){
- DDLog(@"数据为空,写入失败");
- return;
- }
- if (self.peripheral == nil || self.characteristic == nil) {
- DDLog(@"代理为空,写入失败");
- return;
- }
-
-
- [self.peripheral writeValue:data forCharacteristic:self.characteristic type:CBCharacteristicWriteWithResponse];
- }
- #pragma mark 解析设备回复
- - (void)p_receiveData:(NSData *)data{
-
- RDS_WEAKSELF(weakSelf)
- [RDSDeviceCmd rds_receiveData:data finish:^(RDSDeviceReply *reply) {
-
- [weakSelf p_cmdResponce:reply];
- }];
-
-
- }
- #pragma mark - 蓝牙配置和操作
- #pragma mark - CBCentralManagerDelegate
- /** 手机蓝牙状态 */
- -(void)centralManagerDidUpdateState:(CBCentralManager *)central{
- if (central.state == CBManagerStateUnknown) {
- NSLog(@"系统蓝牙当前状态不明确");
- }else if (central.state == CBManagerStateResetting){
- NSLog(@"系统蓝牙设备正在被重置");
- }else if (central.state == CBManagerStateUnsupported){
- NSLog(@"系统蓝牙设备不支持");
- }else if (central.state == CBManagerStateUnauthorized){
- NSLog(@"系统蓝未被授权");
- }else if (central.state == CBManagerStatePoweredOff){
- NSLog(@"系统蓝牙关闭了,请先打开蓝牙");
- }else if (central.state == CBManagerStatePoweredOn){
- NSLog(@"系统蓝牙开启");
- //扫描设备
- if(_isBinding){
- [_centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:Server_00FF]] options:nil];
- }
-
- }
- }
- /** 扫描结果 */
- -(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI{
- NSLog(@"%@",advertisementData);
- // C049EFC91660 807D3AE5E5D4
- if ([peripheral.name hasPrefix:self.deviceName]) {
- self.peripheral = peripheral;
- //连接设备
- [central connectPeripheral:peripheral options:nil];
- //停止扫描
- [self.centralManager stopScan];
- }
- }
- /** 连接成功 */
- -(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
- NSLog(@"连接成功");
- // 设置代理
- self.peripheral.delegate = self;
- // 根据UUID来寻找服务
- [self.peripheral discoverServices:@[[CBUUID UUIDWithString:Server_00FF]]];
- }
- /** 连接失败 */
- -(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(nonnull CBPeripheral *)peripheral error:(nullable NSError *)error{
- NSLog(@"连接失败");
- // 断开连接可以设置重新连接
- if(_isBinding){
- [central connectPeripheral:peripheral options:nil];
- }
- }
- /** 断开连接 */
- - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error {
- NSLog(@"断开连接");
- // 断开连接可以设置重新连接
- if(_isBinding){
- [central connectPeripheral:peripheral options:nil];
- }
- }
- #pragma mark - CBPeripheralDelegate
- /** 发现服务 */
- -(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
-
- CBService * __nullable findService = nil;
- // 遍历服务
- for (CBService *service in peripheral.services) {
- NSLog(@"遍历服务 UUID:%@",service.UUID);
- if ([[service UUID] isEqual:[CBUUID UUIDWithString:Server_00FF]]) {
- findService = service;
- }
- }
- if (findService)
- [peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:Characteristic_FF01]] forService:findService];
- }
-
- /** 发现特征回调 */
- - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
-
- // 遍历出所需要的特征
- for (CBCharacteristic *characteristic in service.characteristics) {
- NSLog(@"所有特征:%@", characteristic);
- // 从外设开发人员那里拿到不同特征的UUID,不同特征做不同事情,比如有读取数据的特征,也有写入数据的特征
- if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:Characteristic_FF01]]) {
- self.characteristic = characteristic;
- // 订阅通知
- [self.peripheral setNotifyValue:YES forCharacteristic:self.characteristic];
- }
- }
-
- }
- /** 订阅状态的改变 */
- -(void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
- if (error) {
- NSLog(@"订阅失败");
- NSLog(@"%@",error);
- }
- if (characteristic.isNotifying) {
- NSLog(@"订阅成功");
- BLOCK_SAFE_RUN(_onConnectDeviceSuccessAndCanWrite);
- } else {
- NSLog(@"取消订阅");
- }
- }
- /** 接收到数据回调 */
- - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
- // 拿到外设发送过来的数据
- // NSData *data = characteristic.value;
- // NSString *msg = [[ NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
- // //所有控制符都会被替换成空字符。
- // NSString *jsonString =[msg stringByTrimmingCharactersInSet:[NSCharacterSet controlCharacterSet]];
- //
- // NSLog(@"收到信息 %@",jsonString);
-
- [self p_receiveData:characteristic.value];
- }
- /** 写入数据回调 */
- - (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error {
- NSLog(@"写入成功");
- }
- #pragma mark - block 一对多监听回调
- - (void)addObserver:(id)observer callback:(RDSCmdTouchResponce)callback {
- // 这里要打破循环引用,因为关联代码中 watch 被 observer 持有,而 watch 中的 callback 去调用了 observer
- __weak typeof (observer) weakObserver = observer;
- RDSDeallocWatcher *watch = [[RDSDeallocWatcher alloc] initWithDeallocCallback:^{
- __strong typeof (observer) strongObserver = weakObserver;
- [self removeObserver:strongObserver];
- }];
- [self.blockTable setObject:callback forKey:observer];
- // 将 observer 与 watch 进行绑定关联,key 则使用 observer 的打印地址
- objc_setAssociatedObject(observer, [[NSString stringWithFormat:@"%p", &observer] UTF8String], watch, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- }
- - (void)addObserver:(id)observer block:(RDSDisconnectDeviceBlock)block {
- // 这里要打破循环引用,因为关联代码中 watch 被 observer 持有,而 watch 中的 callback 去调用了 observer
- __weak typeof (observer) weakObserver = observer;
- RDSDeallocWatcher *watch = [[RDSDeallocWatcher alloc] initWithDeallocCallback:^{
- __strong typeof (observer) strongObserver = weakObserver;
- [self removeObserver:strongObserver];
- }];
- [self.blockTableDisconnect setObject:block forKey:observer];
- // 将 observer 与 watch 进行绑定关联,key 则使用 observer 的打印地址
- objc_setAssociatedObject(observer, [[NSString stringWithFormat:@"%p", &observer] UTF8String], watch, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- }
- - (void)removeObserver:(id)observer {
- [self.blockTable removeObjectForKey:observer];
- objc_setAssociatedObject(observer, [[NSString stringWithFormat:@"%p", &observer] UTF8String], nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
-
-
- [self.blockTableDisconnect removeObjectForKey:observer];
- objc_setAssociatedObject(observer, [[NSString stringWithFormat:@"%p", &observer] UTF8String], nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
-
- }
- - (void)p_cmdResponce:(RDSDeviceReply *)reply{
-
- // 回调
- [[[self.blockTable objectEnumerator] allObjects] enumerateObjectsUsingBlock:^(RDSCmdTouchResponce callback, NSUInteger idx, BOOL * _Nonnull stop) {
- callback(reply);
- }];
-
-
- }
- // block 一对多监听设备信息回调
- - (void)rds_cmdResponceObserve:(id)observe responce:(RDSCmdTouchResponce)responceBlock{
-
- if (observe == nil) {
- return;
- }
- [self addObserver:observe callback:responceBlock];
- }
- - (void)rds_disconnectDeviceObserve:(id)observe block:(RDSDisconnectDeviceBlock)block{
- if (observe == nil) {
- return;
- }
- [self addObserver:observe block:block];
- }
- - (void)p_disconnectDevice{
-
- [[[self.blockTableDisconnect objectEnumerator] allObjects] enumerateObjectsUsingBlock:^(RDSDisconnectDeviceBlock block, NSUInteger idx, BOOL * _Nonnull stop) {
- block();
- }];
-
- }
- @end
|