最近做的项目主要是iphone与平常的一些设备进行蓝牙连接,通信等功能。所以整理了一下蓝牙方面的一些知识。
iOS蓝牙开发主要有种方式。
1 GameKit.framework iOS7之前的蓝牙通讯框架,从iOS7开始过期,但是目前多数应用还是基于此框架。只能用于iOS设备之间,多用于游戏。
2 MultipeerConnectivity.framework iOS7开始引入的新的蓝牙通讯开发框架,用于取代GameKit。也只能用于iOS设备间,主要用于共享文件。
3 CoreBluetooth.framework 功能强大的蓝牙开发框架,要求设备必须支持蓝牙4.0,可与其他第三方设备进行通信。
4 ExternalAccessory.framework 也可于第三方蓝牙设备交互,但是蓝牙设备必须经过MFI认证,需要有苹果的协议,这就有一定的局限性。
对比明显可以看到CoreBluetooth这个比较好用,并且功能强大,不再局限于iOS设备之间进行传输数据,你可以通过iOS设备向Android、Windows Phone以及其他安装有蓝牙4.0芯片的智能设备传输,因此也是目前智能家居、无线支付等热门智能设备所推崇的技术。我这里介绍一下这个的使用。
CoreBluetooth.framework
从iOS6开始苹果推出了此框架,它专门用于与BLE4.0设备通信,不仅限于iOS设备。
CoreBluetooth框架的核心其实是两个东西,peripheral和central, 可以理解成外设和中心。类似于C/S设计(客户端和服务端),外围设备可以理解为客户端,中央设备可以当作服务端。
外围设备和中央设备在CoreBluetooth中使用CBPeripheralManager和CBCentralManager表示。
CBPeripheralManager:外围设备通常用于发布服务、生成数据、保存数据。外围设备发布并广播服务,告诉周围的中央设备它的可用服务和特征。
CBCentralManager:中央设备使用外围设备的数据。中央设备扫描到外围设备后会就会试图建立连接,一旦连接成功就可以使用这些服务和特征。
外围设备和中央设备之间交互的桥梁是服务(CBService)和特征(CBCharacteristic),二者都有一个唯一的标识UUID(CBUUID类型)来唯一确定一个服务或者特征,每个服务可以拥有多个特征。左侧表示中央设备,右侧为外围设备。
CBCentralManager 中央设备管理,使用外围设备的数据。中央设备扫描到外围设备后会就会试图建立连接,一旦连接成功就可以使用这些服务和特征。
CBPeripheralManager 外围设备管理,通常用于发布服务、生成数据、保存数据。外围设备发布并广播服务,告诉周围的中央设备它的可用服务和特征。
CBPeripheral 外围设备。
CBCentral 中央设备。
CBService与CBMutableServic 服务,其中CBMutableServic 是CBService的子类,只多了一个初始化的方法和两个变量。
CBCharacteristic和CBMutableCharacteristic 特征。其中CBMutableCharacteristic是CBCharacteristic的子类,多了一个初始化的方法和几个变量。
CBUUID uuid帮助类。
CBATTRequest 中央发出的读或者写的请求。
主要说一下中央设备的使用。
iOS 中蓝牙操作主要放在BluetoothManager/GABluetoothManager类中。
该类遵循
CBCentralManagerDelegate 中的方法主要有中央的可用性,扫描到的外围设备,与外围设备连接状态。
CBPeripheralDelegate 中主要是发现服务、特征、描述,读写特征和描述。
self.cbCM = [[CBCentralManager alloc] init];
self.cbCM.delegate = self;
NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO],CBCentralManagerScanOptionAllowDuplicatesKey, nil];
self.cbCM scanForPeripheralsWithServices:nil options:dic];
scanForPeripheralsWithServices方法
第一个参数为想要扫描指定uuid service的外围设备,nil是扫描所有。
第二个参数 扫描选项,
CBCentralManagerScanOptionAllowDuplicatesKey 当指定其为YES时,说明过滤功能是不启用的,也就是说centra每次都能接受到来自peripherals的广播包数据,这样的话对电池的寿命会有很大的影响。当设定为NO是每次寻找都会合并相同的peripheral。
/**
* 发现外围设备
* @param central 中心管理
* @param peripheral 外围设备
* @param advertisementData 广播数据
* @param RSSI 信号质量(信号强度)
*/
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
测试参数peripheral中的name不能保证是最新的名字(当一个外围设备改变蓝牙名后),所以我们用广播中的数据
advertismentData,广播中的数据是最新的,可以通过广播蓝牙名和service 的uuid。
[self.cbCM stopScan];//停止扫描
[self.cbCM connectPeripheral:device.peripheral
options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBConnectPeripheralOptionNotifyOnDisconnectionKey]];
options中可以设置一些连接设备的初始属性键值如下
NSString *const CBConnectPeripheralOptionNotifyOnConnectionKey;
APP被挂起时,这时如果APP连接到peripheral时,是否要给APP一个提示框,当然是在APP支持后台运行的前期下。
NSString *const CBConnectPeripheralOptionNotifyOnDisconnectionKey;
APP处于挂起状态时,恰好在这个时候断开连接,要不要给APP一个断开提示。这种情况只有指定了该APP指定在后台能够运行时才显示。
NSString *const CBConnectPeripheralOptionNotifyOnNotificationKey;
App处于挂起状态时,是否接受到所有的来自peripheral的包都要弹出提示框。当然这个key值也是以APP能够在后台运行为前期的。
//连接外围设备失败
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
// 连接到外围设备
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
连接成功后,发现services
设置peripheral的delegate为self非常重要,否则,didDiscoverServices无法回调
peripheral.delegate = self;
[peripheral discoverServices:nil];参数指定service uuid,nil时则不限制uuid。
//已搜索到services
- (void) peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
验证service uuid 是否是我们需要的uuid,如果正确则发现特征。
[peripheral discoverCharacteristics:nil forService:service];可以指定characteristic的uuid。
//已搜索到Characteristics
- (void) peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
验证characteristic uuid是否正确,正确则发送数据,订阅特征。
验证characteristic正确后,先订阅此characteristic
[peripheral setNotifyValue:YES forCharacteristic:c];这样就可以监听characteristic 值的改变了,改变时会回调下面方法:
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
然后发送数据给外围设备。
NSString *str = [NSString stringWithFormat:@"<%@>%@", (hasbond ? @"connect" : @"bind"), self.myUUID];
NSData *data =[str dataUsingEncoding:NSUTF8StringEncoding];
[peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
参数CBCharacteristicWriteWithResponse,则需要外围设备回应write请求。