专栏名称: Cocoa开发者社区
CocoaChina苹果开发中文社区官方微信,提供教程资源、app推广营销、招聘、外包及培训信息、各类沙龙交流活动以及更多开发者服务。
目录
相关文章推荐
51好读  ›  专栏  ›  Cocoa开发者社区

iOS蓝牙开发 Bluetooth蓝牙CoreBluetooth 蓝牙中心设备的实现 蓝牙外设的实现 有Demo

Cocoa开发者社区  · 公众号  · ios  · 2017-07-20 11:06

正文

转载请注明本文地址: http://www.jianshu.com/p/38a4c6451d93


目的


最近公司在做一个iOS蓝牙项目,在开发的过程中简单整理了一些与之相关的基础知识,在这里分享一下。整理包括以下内容:


1、iOS蓝牙开发的关键词

2、蓝牙的简单介绍

3、CoreBluetooth框架

4、实现iOS蓝牙外设( Demo

5、实现iOS蓝牙中心设备( Demo


点击查看 Demo的运行gif图 ,中心设备可以从外设读取数据,也可以向外设写入数据。外设也可以向中心设备发送数据。


PS:需要使用真机测试。


iOS的蓝牙开发是围绕着CoreBluetooth框架来实现的。


下面先从iOS蓝牙开发的基本概念说起。


iOS蓝牙开发的关键词


中心设备:就是用来扫描周围蓝牙硬件的设备,比如通过你手机的蓝牙来扫描并连接智能手环,这时候你的手机就是中心设备。


外设:被扫描的设备。比如当你用手机的蓝牙扫描连接智能手环的时候,智能手环就是外设。


中心设备和外设


广播:就是外设不停的散播蓝牙信号,让中心设备可以扫描到。


外设广播


服务(services):外设广播和运行的时候会有服务,可以理解成一个功能模块,中心设备可以读取服务。外设可以有多个服务。


特征(characteristic):在服务中的一个单位,一个服务可以有多个特征,特征会有一个value,一般读写的数据就是这个value。


服务和特征.png


UUID:区分不同的服务和特征,可以理解为服务和特征的身份证。我们可以用UUID来挑选需要的服务和特征。


蓝牙的简单介绍


偷个懒: 蓝牙百科

蓝牙( Bluetooth® ):是一种短距离无线通信技术 ,可实现固定设备、移动设备和楼宇个人域网之间的短距离数据交换(使用2.4—2.485GHz的ISM波段的UHF无线电波)。蓝牙4.2发布于2014年12月2日,本文发布的时候,蓝牙的最新版本为4.2。


CoreBluetooth框架


蓝牙开发层次图


如上图所示,iOS中的蓝牙开发框架CoreBluetooth处在蓝牙低功耗协议栈的上面,我们开发的时候只是使用CoreBluetooth这个框架,通过CoreBluetooth可以轻松实现外设或中心设备的开发。


CoreBluetooth可以分为两大模块,中心设备central,外设peripheral,它们俩各有自己的一套API供我们使用。


中心设备和外设使用.png


上图左边的就是中心设备的开发类,我们平时是使用CBCentralManager来进行相关操作。


CBCentralManager: 蓝牙中心设备管理类,用来统一调度中心设备的开发

CBPeripheral :蓝牙外设,例如蓝牙手环、心率监测仪。

CBService :蓝牙外设的服务,可以有0个或者多个服务。

CBCharacteristic :服务中的特征,每一个蓝牙服务中可以有0个或多个特征,特征中包含数据信息。

CBUUID:可以理解为服务或特征的身份证,可以用来选择需要的服务和特征。


右边是外设开发相关类,一般是围绕着CBPeripheralManager来进行编码。


CBPeripheralManager: 蓝牙外设开发时使用,用来开发蓝牙外设的中心管理类。

CBCentral:蓝牙中心设备,例如用来连接蓝牙手环的手机。

CBMutableService:外设开发的时候可以添加多个服务,所有这里用CBMutableService来创建添加服务。

CBMutableCharacteristic:每个服务中可以有多个特征,外设开发给服务添加特征的时候使用这个类。

CBATTRequest:读或者写请求。它的实例对象有一个value属性,用来装载外设进行蓝牙读取或写入请求时的数据。一般在外设写入或读取的回调方法中有这一个参数。


外设添加服务和特征


实现iOS蓝牙外设( Demo


外设管理器


1、首先导入CoreBluetooth框架,并遵守协议


#import

// 遵守CBPeripheralManagerDelegate协议

@interface ViewController ()


2、创建外设管理对象,用一个属性来强引用这个对象。并且在创建的时候设置代理,声明放到哪个线程。


@property (nonatomic, strong) CBPeripheralManager *peripheralManager;


// 创建外设管理器,会回调peripheralManagerDidUpdateState方法

self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()];


3、当创建CBPeripheralManager的时候,会回调判断蓝牙状态的方法。当蓝牙状态没问题的时候创建外设的Service(服务)和Characteristics(特征)。


/*

设备的蓝牙状态

CBManagerStateUnknown = 0,  未知

CBManagerStateResetting,    重置中

CBManagerStateUnsupported,  不支持

CBManagerStateUnauthorized, 未验证

CBManagerStatePoweredOff,   未启动

CBManagerStatePoweredOn,    可用

*/

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

if (peripheral.state == CBManagerStatePoweredOn) {

// 创建Service(服务)和Characteristics(特征)

[self setupServiceAndCharacteristics];

// 根据服务的UUID开始广播

[self.peripheralManager startAdvertising:@{CBAdvertisementDataServiceUUIDsKey:@[[CBUUID UUIDWithString:SERVICE_UUID]]}];

}

}


可以先用宏来做两个标识字符串,用来创建服务和特征的UUID。


最终把创建好的特征放进服务,把服务放入中心管理器。


#define SERVICE_UUID @"CDD1"

#define CHARACTERISTIC_UUID @"CDD2"


/** 创建服务和特征 */

- (void)setupServiceAndCharacteristics {

// 创建服务

CBUUID *serviceID = [CBUUID UUIDWithString:SERVICE_UUID];

CBMutableService *service = [[CBMutableService alloc] initWithType:serviceID primary:YES];

// 创建服务中的特征

CBUUID *characteristicID = [CBUUID UUIDWithString:CHARACTERISTIC_UUID];

CBMutableCharacteristic *characteristic = [

[CBMutableCharacteristic alloc]

initWithType:characteristicID

properties:

CBCharacteristicPropertyRead |

CBCharacteristicPropertyWrite |

CBCharacteristicPropertyNotify

value:nil

permissions:CBAttributePermissionsReadable |

CBAttributePermissionsWriteable

];

// 特征添加进服务

service.characteristics = @[characteristic];

// 服务加入管理

[self.peripheralManager addService:service];


// 为了手动给中心设备发送数据

self.characteristic = characteristic;

}


注意CBCharacteristicPropertyNotify这个参数,只有设置了这个参数,在中心设备中才能订阅这个特征。


一般开发中可以设置两个特征,一个用来发送数据,一个用来接收中心设备写过来的数据,我们这里为了方便就只设置了一个特征。


最后用一个属性拿到这个特征,是为了后面单独发送数据的时候使用,数据的写入和读取最终还是要通过特征来完成。


4、当中心设备读取这个外设的数据的时候会回调这个方法。


/** 中心设备读取数据的时候回调 */

- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request {

// 请求中的数据,这里把文本框中的数据发给中心设备

request.value = [self.textField.text dataUsingEncoding:NSUTF8StringEncoding];

// 成功响应请求

[peripheral respondToRequest:request withResult:CBATTErrorSuccess];

}


5、当中心设备写入数据的时候,外设会调用下面这个方法。


/** 中心设备写入数据的时候回调 */

- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests {

// 写入数据的请求

CBATTRequest *request = requests.lastObject;

// 把写入的数据显示在文本框中

self.textField.text = [[NSString alloc] initWithData:request.value encoding:NSUTF8StringEncoding];

}


6、还有一个主动给中心设备发送数据的方法。


/** 通过固定的特征发送数据到中心设备 */

- (IBAction)didClickPost:(id)sender {

BOOL sendSuccess = [self.peripheralManager updateValue:[self.textField.text dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.characteristic onSubscribedCentrals:nil];

if (sendSuccess) {

NSLog(@"数据发送成功");

}else {

NSLog(@"数据发送失败");

}

}


7、中心设备订阅成功的时候回调。


/** 订阅成功回调 */

-(void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic {

NSLog(@"%s",__FUNCTION__);

}


8、中心设备取消订阅的时候回调。


/** 取消订阅回调 */

-(void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic {







请到「今天看啥」查看全文