iOS蓝牙4.0开发(一)与外设通讯

蓝牙协议本身经历了从1.04.0的升级演变,最新的4.0以其低功耗著称,所以一般也叫BLE(Bluetoothlow energy)


iOS有两个框架支持蓝牙与外设连接。一个是 ExternalAccessory。从ios3.0就开始支持,也是在iphone4s出来之前用的比较多的一种模式,但是它有个不好的地方,External Accessory需要拿到苹果公司的MFI认证。


另一个框架则是本文要介绍的CoreBluetooth,iphone4s开始支持,专门用于与BLE设备通讯(因为它的API都是基于BLE的)。这个不需要MFI,并且现在很多蓝牙设备都支持4.0,所以也是在IOS比较推荐的一种开发方法。


CoreBluetooth框架的核心其实是两个东西,peripheralcentral,可以理解成外设和中心。对应他们分别有一组相关的API和类。


周边(Peripheral)是生成或者保存了数据的设备,中央(Central)是使用这些数据的设备。所有可用的iOS设备可以作为周边(Peripheral)也可以作为中央(Central),但不可以同时既是周边也是中央。


周边和中央这两个角色在CoreBluetooth框架中是用两个类来表示的,CBPeripheralManager这个类代表周边,CBCentralManager这个类代表中央。

在中央这边,一个CBPeripheral对象代表着相应的和中央连接着的周边;同样的,在周边这边,一个CBCentral 对象代表着相应的和周边连接着的中央。

你可以认为周边是一个广播数据的设备,他广播到外部世界说他这儿有数据,并且也说明了能提供的服务。另一边,中央开始扫描附近有没有服务,如果中央发现了想要的服务,然后中央就会请求连接周边,一旦连接建立成功,两个设备之间就开始交换传输数据了。


在中央这边,CBService类代表服务,CBCharacteristic 类代表特征。

在周边这边,CBMutableService类代表服务,CBMutableCharacteristic 类代表特征。


每个蓝牙4.0的设备都是通过服务和特征来展示自己的,一个设备必然包含一个或多个服务,每个服务下面又包含若干个特征。特征是与外界交互的最小单位。比如说,一台蓝牙4.0设备,用特征A来描述自己的出厂信息,用特征B来与收发数据等。

每一个服务和特征都需要用一个UUIDunique identifier)去标识,UUID是一个16bit或者128bit的值。如果你要创建你的中央-周边App,你需要创建你自己的128bitUUID。你必须要确定你自己的UUID不能和其他已经存在的服务冲突。如果你正要创建一个自己的设备,需要实现标准委员会需求的UUID;如果你只是创建一个中央-周边App,我建议你打开Mac OS XTerminal.app,用uuidgen命令生成一个128bitUUID。你应该用该命令两次,生成两个UUID,一个是给服务用的,一个是给特征用的。然后,你需要添加他们到中央和周边App中。


蓝牙设备硬件厂商通常都会提供他们的设备里面各个服务(service)和特征(characteristics)的功能,比如哪些是用来交互(读写),哪些可获取模块信息(只读)等。


app和硬件之间通讯,app的角色是central,硬件的角色就是peripheral,如果是appapp之间通讯,那么一个iOS设备是central,另一个iOS设备就是peripheral了。这里要介绍的是app和硬件之间的通讯,也就是介绍central,下一节,我们会通过介绍两个iOS设备之间的蓝牙通讯来详细介绍peripheral


实现细节

作为一个中心要实现完整的通讯,一般要经过这样几个步骤:


建立中心角色扫描外设(discover连接外设(connect)—扫描外设中的服务和特征(discover)—与外设做数据交互(explore and interact)—断开连接(disconnect)


首先在我自己类的头文件中要包含CoreBluetooth的头文件,并继承两个协议CBCentralManagerDelegate, CBPeripheralDelegate


1.创建我们的中心角色

CBCentralManagerDelegate协议委托给当前类实例,这里有个@required协议方法

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

当中心角色的状态发生变化的时候会触发这个方法。在这个方法中通过获取中心角色的状态来对它发布命令,你只能在central的state是CBCentralManagerStatePoweredOn的时候对它发布命令,当status的值低于CBCentralManagerStatePoweredOn的时候意味着扫描停止,并且任何已连接的外设都已经断开,当status的值低于CBCentralManagerStatePoweredOff时,所有的外设对象将从中心角色中作废,而且必须重新被发现。

_centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];


2.扫描外设

创建中心角色以后,我们在centralManagerDidUpdateState:方法中获取central的status是CBCentralManagerStatePoweredOn的时候来扫描外设

[self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]
                                                options:@{ CBCentralManagerScanOptionAllowDuplicatesKey : @YES }];


这里的TRANSFER_SERVICE_UUID就是硬件厂商提供的服务UUID,如果第一个参数指定为空,那么所有的外设服务将被返回(不推荐)


3.连接外设

当扫描到外设以后,系统会通过以下代理方法

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

告诉我们设备的信息,然后我们就可以连接相应的设备,我们可以通过RSSI.integerValue来获取信号强度,在这个方法中,我们可以连接我们想要连接的外设,代码如下:
[self.centralManager connectPeripheral:peripheral options:nil];

如果连接失败,会触发代理方法

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

如果连接成功,会触发代理方法:

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

我们可以在这里扫描外设中的服务。


4.扫描外设中的服务和特征

[peripheral discoverServices:@[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]];

如果参数为空,将会返回外设中所有可用的服务。通过如下代理方法返回被扫描的服务。

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error;

如果error不为空,则扫描失败,反之,扫描成功,我们可以继续扫描服务中的特征

[peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]] forService:service];

这里的TRANSFER_CHARACTERISTIC_UUID就是硬件厂商提供的特征UUID,如果第一个参数指定为空,那么所有的该服务的特征将被返回。

通过如下代理方法返回被扫描的特征。

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

如果error不为空,则扫描失败,反之,扫描成功,我们可以继续枚举服务中的特征,我们通过CBCharacteristic的properties来读取特征的属性,

typedef NS_OPTIONS(NSUInteger, CBCharacteristicProperties) {
	CBCharacteristicPropertyBroadcast									= 0x01,
	CBCharacteristicPropertyRead										= 0x02,
	CBCharacteristicPropertyWriteWithoutResponse								= 0x04,
	CBCharacteristicPropertyWrite										= 0x08,
	CBCharacteristicPropertyNotify										= 0x10,
	CBCharacteristicPropertyIndicate									= 0x20,
	CBCharacteristicPropertyAuthenticatedSignedWrites							= 0x40,
	CBCharacteristicPropertyExtendedProperties								= 0x80,
	CBCharacteristicPropertyNotifyEncryptionRequired NS_ENUM_AVAILABLE(NA, 6_0)		= 0x100,
	CBCharacteristicPropertyIndicateEncryptionRequired NS_ENUM_AVAILABLE(NA, 6_0)	= 0x200
};


数据的读分为两种,一种是直接读,另外一种是通知。当属性为CBCharacteristicPropertyRead是可读CBCharacteristicPropertyNotify是可通知,

当特征的属性是可通知的时候,我们通过如下设置来支持通知,如果你希望特征的value发生变化的时候我们被告知,就要设置YES,反之为NO

[peripheral setNotifyValue:YES forCharacteristic:characteristic];

这个设置会通过以下代理方法来告知是否设置成功,如果设置成功,error为nil,反之失败。

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

设置成功以后,会通过以下代理方法告知我们characteristic的value发生变化,同样地,这个代理方法也会在你调用readValueForCharacteristic:方法的时候被触发。

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


5.与外设做数据交互

读上面已经讲到。

写数据:

[_discoveredPeripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];

通过CBCharacteristicWriteWithResponse属性,我们可以通过以下代码方法被告知数据是否发送成功,error为空则成功,否则失败。

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


6.断开连接

[self.centralManager cancelPeripheralConnection:peripheral];


我们可以通过以下代码方法被告知是否断开成功,error为空则成功,否则失败。

- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;



参考资料

http://www.2cto.com/kf/201405/303572.html

http://blog.csdn.net/chenli522/article/details/17114417

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值