美文网首页
iOS 蓝牙初探

iOS 蓝牙初探

作者: 小白e7899 | 来源:发表于2020-04-01 17:23 被阅读0次

    题外话:

    两个月多月之前,华夏大地有多危险?

    如果武汉没有封城、如果湖北没有封省、如果春节期间坚持走亲串户。

    那么,现在欧洲处境就是我们处境。医疗资源耗尽、医疗体系崩溃、不断有人离去。真的不敢往下想。

    如今,正式大家努力,让中国变成世界最安全的国家。从“危”转“机”。

    而我本人也经历了一场“危”“机”,虽然跟新冠病毒没有直接关系。去年的项目因为各种原因,团队解散,在一次面临着失业。

    好在朋友介绍,顺利尽力新公司,开始新的征程。

    原生开发做了几年,其实涉及的内容并不多,无非就是界面的布局,与服务器做交互等待相关事情。

    新岗位也是开发相关的,但是一开就是蓝牙通讯,这个之前未曾涉及。也很久没有更新博客,这篇文章算是做个记录:


    做蓝牙开发,如果没有看过苹果的蓝牙相关的文档,个人建议先去看苹果的官方文档,虽然全市英文,啃完以后会清楚很多。以下是苹果官方文档的地址:

    https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/PerformingCommonCentralRoleTasks/PerformingCommonCentralRoleTasks.html#//apple_ref/doc/uid/TP40013257-CH3-SW1

    看完官方文档以后,可以看看别人的翻译和理解,这个也是很有帮助的:

    http://www.saitjr.com/ios/core-bluetooth-overview.html

    蓝牙开发其实也不难,个人理解大概可以分按照下面的思路进行:

    打开蓝牙--搜索外设--连接--获取外设的服务--获取服务的特征--绑定通知--读写数据--断开连接

    1 判断设备是否有蓝牙功能,即CBManagerState,如果设备都没蓝牙,其他都是纸上谈兵。只有设备支出蓝牙并且出于开启状态才能往下进行。

    2 蓝牙连接的2端分为 中心和外设,中心Central:接收数据就是中心,外设Peripheral:发送数据就是外设。正常的开发中,手机是作为中心。蓝牙框架中,中心、外设都是对象,相关的方法是通过协议(代理)完成。

    3 中心要搜索正在广播的蓝牙设备,那么要先有个中心对象,Central对象调用scanForPeripheralsWithServices:options 方法搜索,第一个参数传入要搜索的蓝牙设备UUID数组,如果没有传,则会搜索正在广播的所有蓝牙设备,第二参数一般为nil,表示在主线操作。

    4 只有中心搜索到外设,会调用(搜索到一个调用一次)centralManager:centraldidDiscoverPeripheral:peripheraladvertisementData:advertisementDataRSSI: 

    5 找到自己需要的外设,中心调用connectPeripheral: options:nil连接

    连接成功调用centralManager: didConnectPeripheral:  这个时候可以搜索外设的服务:外设调用discoverServices方法,可以传入外设服务uuid,如果没有传则搜索所有服务。

    连接失败:centralManager: didFailToConnectPeripheral: error:

    断开连接:centralManager: didDisconnectPeripheral: error:

    6 连接成功,获取外设的服务,如果上面提到的discoverServices的方法有传入参数,就可以直接找服务的特征,如果没有传,这里要遍历服务,找到需要的服务,发现服务的方法外设的代理方法:peripheral: didDiscoverServices:  发现了服务:紧接着是特征:外设discoverCharacteristics:nil forService:发现对象服务的特征,

    7 发现特征以后,调用peripheral:didDiscoverCharacteristicsForService: error:这里要根据自己开发中的蓝牙协议,哪些是特征是可以订阅的,哪些是特征是可以写的,哪些特征是可以读的(很少用)

    8 特征订阅是否成功都会调用peripheral: didUpdateNotificationStateForCharacteristic: error:

    9 写入成功回调方法:peripheral:didWriteValueForDescriptor:error:

    外设写入数据的方法:writeValue:forCharacteristic: type:

    10 收到蓝牙数据回调方法:peripheral:didUpdateValueForCharacteristic: error:

    如果看过官方文档,获取随便度娘找,做到这一步应该都没问题,

    实际开发中,最主要的是写入数据的方法(writeValue:forCharacteristic: type:),以及收到数据的方法:peripheral:didUpdateValueForCharacteristic: error:

    至于用什么格式写入什么数据,要根据自己的协议完成,转成NSData在写入

    收到数据的处理,也要自己的协议,完成解析,才能拿到数据。

    代买如下:

    - (void)centralManagerDidUpdateState:(nonnull CBCentralManager *)central {

        // 更新中心蓝牙状态回调 central.state == CBManagerStatePoweredOn 才是可用的

    }

    // 扫描到外设,

    - (void)centralManager:(CBCentralManager*)centraldidDiscoverPeripheral:(nonnullCBPeripheral*)peripheraladvertisementData:(nonnullNSDictionary *)advertisementDataRSSI:(nonnullNSNumber*)RSSI {

        NSLog(@"%@", peripheral.name);

       //        这里要找到自己的需要的外设才能连接

            self.peripheral= peripheral;

            [centralconnectPeripheral:peripheraloptions:nil];

    }

    // 链接成功,调用下面的方法

    - (void)centralManager:(CBCentralManager*)centraldidConnectPeripheral:(CBPeripheral*)peripheral {

    //    NSLog(@"外设连接成功,先停止扫描");

        // 链接成功,出于对性能的考虑,应该停止扫描

        [self.centralManager stopScan];

        // 设置外设代理

        peripheral.delegate=self;

            // 根据uuid来寻找服务  这个参数不能为空,否则会崩

        [peripheraldiscoverServices:nil];

    }

    - (void)centralManager:(CBCentralManager*)centraldidFailToConnectPeripheral:(CBPeripheral*)peripheralerror:(NSError*)error {

        NSLog(@"连接失败");

    }

    - (void)centralManager:(CBCentralManager*)centraldidDisconnectPeripheral:(CBPeripheral*)peripheralerror:(NSError*)error {

        NSog(@"连接断开");

    }

    #pragma mark CBPeripheralDelegate  外设代理方法

    // 发现服务  回调

    - (void)peripheral:(CBPeripheral*)peripheraldidDiscoverServices:(NSError*)error {

        if(error) {

            PLog(@"发生错误");

        }else{

            // 在这里遍历服务,找到需要的服务

            [peripheral.servicesenumerateObjectsUsingBlock:^(CBService*obj,NSUIntegeridx,BOOL*stop) {

                CBService*service = obj;

                if([obj.UUID.UUIDStringisEqual:SERVICES_UUID]) {

                    [self.peripheral discoverCharacteristics:nil forService:service];

                }

            }];

        }

    }

    // 发现特征  回调

    - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(nonnull CBService *)service error:(nullable NSError *)error {

        // 遍历特征

        [service.characteristicsenumerateObjectsUsingBlock:^(CBCharacteristic*_Nonnullobj,NSUIntegeridx,BOOL*_Nonnullstop) {

            if([obj.UUID.UUIDStringisEqual:ChAR_NOTIFY_UUID]) {// 支持订阅

                self.bleNotifyChar= obj;

                // 开启通讯通道

                [peripheral setNotifyValue:YES forCharacteristic:obj];

            }

            if([obj.UUID.UUIDStringisEqual:CHAR_WRITE_UUID]) {// 支持写入

                self.bleWriteChar = obj;

            }

        }];

    }

    // 订阅状态发送改变,调用下面这个方法

    - (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error {

        if(error) {

            NSLog(@"订阅失败----%@", error);

            return;

        }

        NSString*rst = characteristic.isNotifying?@"订阅成功 -------->    读取数据":@"取消订阅";

        NSLog(@"%@", rst);

    }

    // 接收到数据回调

    - (void)peripheral:(CBPeripheral*)peripheraldidUpdateValueForCharacteristic:(CBCharacteristic*)characteristicerror:(NSError*)error {

        if(error) {

            PLog(@"发生错误了");

            return;

        }

        NSData*data = characteristic.value;

        // 只有当返回的数据不为空,并且回调有实现才执行回调

        NSString*str = [Tools convertDataToHexStr:data];

    }

    - (void)peripheral:(CBPeripheral*)peripheraldidWriteValueForDescriptor:(CBDescriptor*)descriptorerror:(NSError*)error {

        NSLog(@"写入成功");

    }

    相关文章

      网友评论

          本文标题:iOS 蓝牙初探

          本文链接:https://www.haomeiwen.com/subject/pxsauhtx.html