iOS 蓝牙初探

题外话:

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

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

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

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

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

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

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

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



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

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 蓝牙初探)