iOS蓝牙开发(结合智能硬件)

在现在这份工作之前做了挺长时间的“智能门禁”“智能家居”方面的Ios开发,都是基于sip协议实现的手机与硬件设备的交互。用到的开源库分别是idoubs(doubango)、linphone,相比较而言linphone的通话效果会好些也更稳当一些。

在软硬件结合的产品中蓝牙开发是必不可少的,因为蓝牙是一种短距离、高效、无需网络的通讯方式。Ios蓝牙分为“中心者模式“和”外设模式“。前者是将手机作为蓝牙信号的接收端,用来连接蓝牙设备并实现手机与外设间的数据传递。后者是将手机作为蓝牙信号的发射端,无需连接蓝牙设备而只需通过发送广播包的形式将数据(加密)广播出去即可,外设中的蓝牙模块在接收到该数据后进行解密->信息比对,进而进行其他操作。

中心者模式 

这里需要使用到CoreBluetooth.framework中的CBCentralManager、CBPeripheral两个类,分别用来连接蓝牙和读写蓝牙传递的数据。

蓝牙连接:

1、创建蓝牙管理对象

CBCentralManager *manager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue() options:nil];

opetion: 设置系统自带选项

CBCentralManagerOptionShowPowerAlertKey   默认为NO即若手机蓝牙未打开则不弹框提示,可设置为YES CBCentralManagerOptionRestoreIdentifierKey   app被杀死,重新恢复manager的ID CBCentralManagerScanOptionAllowDuplicatesKey   默认为NO,过滤功能是否启用,每次寻找都会合并相同的peripheral。如果设为YES的话每次都能接受到来自peripherals的广播包数据。

CBCentralManagerScanOptionSolicitedServiceUUIDsKey   扫描的时候只会扫描到包含这些UUID的设备(数组)。CBConnectPeripheralOptionNotifyOnConnectionKey   默认为NO,APP被挂起时如果已连接到peripheral,是否要给APP一个提示框。

CBConnectPeripheralOptionNotifyOnDisconnectionKey 默认为NO,APP被挂起时,恰好在这个时候断开连接,要不要给APP一个断开提示。

CBConnectPeripheralOptionNotifyOnNotificationKey 默认为NO,APP被挂起时,是否接受到所有的来自peripheral的包都要弹出提示框。

2、检测手机蓝牙状态并扫描蓝牙设备

#pragma mark CBCentralManagerDelegate

//上面创建中心管理者后 这里会自动监测蓝牙的使用状态

- (void)centralManagerDidUpdateState:(CBCentralManager *)central;

根据central.state状态值判断:

CBCentralManagerStateUnknown未知状态/CBCentralManagerStateResetting复位/CBCentralManagerStateUnsupported不支持/CBCentralManagerStateUnauthorized未授权/CBCentralManagerStatePoweredOff未开启/CBCentralManagerStatePoweredOn已开启

在蓝牙开启后执行[manager scanForPeripheralsWithServices:nil options:nil];搜索全部蓝牙 或 [manager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:@"EEFF"]] options:nil];搜索指定UUID的蓝牙。

3、连接蓝牙设备

//发现外设

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI

{  //接下来在这里根据获取的外设peripheral信息对搜索到的(符合特定服务)蓝牙做筛选。 

if([peripheral.name isEqualToString:@"TESTNAME"]) {

[self.centralManager connectPeripheral:peripheral options:nil];    //连接

[self.centralManager stopScan];  }}         //停止扫描

4、检测与蓝牙设备的连接状态

//中心管理者连接外设成功

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{

 //到这里上面中心管理者的代理方法就执行完了,并且已经连接到了指定的蓝牙设备,所以下面要设置_peripheral的代理并开始读取蓝牙携带的数据。

[peripheral setDelegate:self];

[peripheral discoverServices:nil]; //搜索该蓝牙对应的所有服务

}

//外设连接失败

- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{

NSLog(@"%s, line = %d, %@=连接失败", __FUNCTION__, __LINE__, peripheral.name);

}

//丢失连接- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{

NSLog(@"%s, line = %d, %@=断开连接", __FUNCTION__, __LINE__, peripheral.name);

[self.centralManager connectPeripheral:peripheral options:nil];               //重新连接

}

读写蓝牙数据

5、搜索蓝牙特征

//已经发现该蓝牙对应的服务(根据蓝牙设备搜索服务)

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(nullable NSError *)error{

for(CBService *service in _peripheral.services) {

[_peripheral discoverCharacteristics:nil forService:service]; //搜索service服务对应的特征

}}

6、根据特征属性做对应的读写操作

//已经搜索到服务对应的特征(根据服务搜索特征,然后判断特征是否可读、可写,最后根据特征的读写属性进行写入和读取操作)

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

for(CBCharacteristic *characteristic in service.characteristics) {

if((unsigned long)characteristic.properties == 10) { //支持读写的属性对应的特征才能写入数据

[peripheral writeValue:[_inputStr dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse]; //将数据写入指定的特征(即给蓝牙设备发送数据)

}}}

7、检测是否读写成功

//用于检测中心向外设写数据是否成功

-(void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{

if (error) {

NSLog(@"写入蓝牙特征数据失败 = %@",error.userInfo); }

else{

NSLog(@"写入蓝牙特征数据成功"); } 

[peripheral readValueForCharacteristic:characteristic];}

8、订阅特征并实时更新数据

- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error;

外设模式

这里需要用到CoreBluetooth.framework中的CBPeripheralManager类,把手机作为蓝牙广播包的发送者。

1、创建设备类对象并检测手机蓝牙状态

CBPeripheralManager *manager = [[CBPeripheralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue() options:nil];

#pragma mark CBPeripheralMangerDelegate

- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral;

2、发广播包

[manager startAdvertising:@{CBAdvertisementDataLocalNameKey : @"将显示的蓝牙名称", CBAdvertisementDataServiceUUIDsKey:@"自定义的UUID"}];

注:startAdvertising这个方法只允许设置CBAdvertisementDataLocalNameKey(本地名称)、CBAdvertisementDataServiceUUIDsKey(UUID)两个参数,其他键值key可在“中心模式”下的设备中查看使用。 CBAdvertisementDataIsConnectable(外设的可连接数)这个参数是广播包自带的默认参数(1->可连接 0->不可连接)。广播包中能传输的数据最多为32个字节。

3、检测手机广播是否成功

//手机已经开始广播广播

- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(nullable NSError *)error;

下面简要说明下我们产品的蓝牙应用场景

“中心者模式”:

步骤:开启蓝牙->搜索固定标示的蓝牙设备->连接蓝牙->向蓝牙模块写入加密指令->蓝牙模块将指令信息输出到硬件主板->执行具体操作

注:为了用户有更好的使用体验,这里的连接蓝牙是自动连接即连接时无需授权(蓝牙模块开发人员处理),且为了保证蓝牙连接的稳定性我们使用的蓝牙最大连接数为一个。

“外设模式”:

步骤:开启蓝牙->将带有固定标示的加密数据写入广播包的CBAdvertisementDataLocalNameKey中->硬件中的蓝牙模块识别到该数据包并将相关数据输出到主板->解密数据并执行相应操作

注:这个方式需要和蓝牙模块开发人员、硬件开发人员共同制定数据传输协议

你可能感兴趣的:(iOS蓝牙开发(结合智能硬件))