本⽂文是苹果《Core Bluetooth Programming Guide》的翻译。

关于Core Bluetooth

Core Bluetooth 框架提供了蓝⽛牙低功耗⽆无线设备与 iOS 应⽤用或 Mac 应⽤用通讯的必要的类。应⽤用可以发现,探索低功耗外设,并与它交互,⽐比如⼼心率监控器和数字 温度调节器。 从 OS X V10.9 和 iOS 6 之后,Mac 和 iOS 设备也能充当蓝⽛牙低功耗外设给包括 Mac 和 iOS 在内的其他设备提供数据服务了。

 

概览

蓝⽛牙低功耗⽆无线技术(BLE)基于蓝⽛牙4.0规范,在其基础上定义了⼤大量低功耗设备之间通信的协议。Core Bluetooth 框架是蓝⽛牙低功耗协议栈的抽象。也就是 说,它对开发者隐藏了规范底层的许多细节,使得你开发与蓝⽛牙低功耗设备通讯的应⽤用变得容易。

主机(Central)和外设(Peripheral)是 Core Bluetooth 的关键⾓角⾊色

在蓝药低功耗通讯中,有两个关键的⾓角⾊色: 主机 和 外设 。⼀一个典型的外设拥有其他设备需要的数据。⼀一个典型的主机使⽤用外设提供的信息完成某些任务。例 如,BLE数字温度调节器可以提供室内温度给⼀一个 iOS 应⽤用,然后应⽤用将温度⽤用⽤用户友好的⽅方式展现出来。 外设在空⽓气中⼲⼴广播数据。⽽而主机可以扫描拥有它感兴趣的数据的外设。当主机发现这样的外设时,主机可以请求连接该外设然后探索和交互。然后外设以主机期 望的⽅方式响应主机的请求。

#### Core Bluetooth 简化了通⽤用的蓝⽛牙任务
Core Bluetooth 框架抽象了蓝⽛牙4.0规范的底层细节。这样应⽤用中需要完成的许多常⽤用的 BLE 任务都变得很简单了。如果你开发的应⽤用是完成蓝⽛牙主机功能,
Core Bluetooth 让它很容易发现和与外设连接,容易探索外设和与外设交互。另外,Core Bluetooth 让你很容易使⽤用本地设备来充当外设。

 

iOS 应⽤用状态影响蓝⽛牙⾏行为

当 iOS 应⽤用处于后台或者挂起状态,与蓝⽛牙相关的功能会受到影响。默认情况下,应⽤用在后台或者挂起状态下不能完成 BLE 任务。如果你的应⽤用需要在后台完成 BLE 任务,你需要声明⼀一个或者全部两个 Core Bluetooth 应⽤用的执⾏行模式(⼀一个是主机,⼀一个是外设)。即使你声明了他们的执⾏行模式,但是当应⽤用在后台时, 某些特定的蓝⽛牙任务操作还是会与前台有所区别。在设计应⽤用时需要注意这些差别。
⽀支持后台处理的应⽤用可能在任何时候被系统终⽌止然后释放内存。⾃自 iOS 7,Core Bluetooth ⽀支持保存主机和外设管理的对象,也⽀支持在应⽤用重启时恢复状态。你可
以使⽤用这个特性来⽀支持必要的⻓长期蓝⽛牙设备任务。

按照最佳实践加强⽤用户体验

Core Bluetooth 框架让你控制许多通⽤用的 BLE 传输。你需要按照最佳实践负责任的完成这个层级的控制,增强⽤用户体验。 例如,许多任务需要使⽤用设备⽆无线电来发射信号,⽽而设备⽆无线电是与其他形式的⽆无线通讯共享的,并且⽆无线电使⽤用对电池的使⽤用寿命有很⼤大的影响,所以设计应用时要尽量减少对无线电的使⽤。

Core Bluetooth 概览

Core Bluetooth 框架让你的 iOS 和 Mac 应⽤用与 BLE 设备通信。例如,你的应⽤用发现,探索,并与 BLE 设备通信(⼼心率监控器,数字温度调节器,甚⾄至其他 iOS 设备)。
Core Bluetooth 框架是对使⽤用低功耗设备的蓝⽛牙4.0规范的抽象。也就是说,它影藏了许多底层细节,开发者使⽤用框架可以更容易的开发与 BLE 交互的应⽤用。因为
框架基于蓝⽛牙4.0规范,所以采⽤用了规范的⼀一些原则和术语。本章介绍关键的术语和原则,这些都是你使⽤用 Core Bluetooth 开发应⽤用时必须清楚的。

 

主机和外设以及他们在蓝⽛通信中扮演的角⾊

在所有的 BLE 通信中有两个主要的概念: 主机 和 外设 。基于⼀一些传统的CS体系, 外设 典型的 拥有其他设备需要的数据 。 主机 典型
的 使⽤用外设提供的信息来完成特定的任务 。如图 1-1 所⽰示,⼀一个⼼心率监控器有些有⽤用的信息,你的 Mac 或 iOS 应⽤用需要这些数据然后将它们友好的展现给用
户。

主机发现和连接发⼲播的外设

外设向外⼲⼴广播⼀一些⼲⼴广播包形式的数据。 ⼲⼴广播包 是外设提供的包含有⽤用信息的⼀一束数据,例如外设的名称和主要功能。举个例⼦子,数字温度调节器可以⼲⼴广播当前 室温。在 BLE,⼲⼴广播是外设被感知存在的主要⽅方式。
主机能够扫描,侦听任何它感兴趣的正在⼲⼴广播的外设。如图 1-2 所⽰示,主机能够请求连接它发现的外设。

外设的数据如何组织

连接外设的⺫⽬目的是为了探索外设并与外设交互数据。在做这个之前,有必要理解外设的数据是怎么组织的。 外设可以包含⼀一个或者多个服务来提供连接信号强度相关的有⽤用的信息。 服务 是 设备完成某功能相关的数据集合或者设备某特征数据的集合 。例如,⼼心率监

控器可以展⽰示来⾃自⼼心率传感器的⼼心率数据。 服务 由 特征(characteristics) 或者 其他服务 组成。 特征 提供外设服务的进⼀一步详情。例如,⼼心率服务 可能仅仅包含⼀一个描述⼼心率传感器预定位置的特征和另外⼀一个发送⼼心率测量数据的特征。图 1-3 列出了⼼心率监控器服务和特征的数据结构。

如何描述主机,外设,外设数据

在 Core Bluetooth 框架中,BLE 的主要参与者和数据都被映射得简单⽽而轻量。

主机端相关对象

使⽤用本地主机与远程外设通信时,你在主机端完成操作。除⾮非你设置⼀一个本地外设,然后使⽤用它响应主机的请求,否则⼤大多数蓝⽛牙传输发⽣生在主机这⼀一端。

本地主机和远程外设

在主机端,本地主机设备⽤用 CBCentralManager 对象表⽰示。这些对象⽤用来管理发现或连接远程外设(远程外设⽤用 CBPeripheral 对象表⽰示),包括扫 描,发现,连接发⼲⼴广播的外设。

图 1-4 显⽰示了 Core Bluetooth 框架中本地主机和远程外设如何表⽰示。

远程外设的数据⽤用 CBService 和 CBCharacteristic 对象表⽰示

当你与远程外设交互数据的时候,实际上是处理它的服务和特征。在 Core Bluetooth 框架中,远程外设的服务⽤用 CBservice 对象表⽰示。类似的,远程外设的特征

⽤用 CBCharacteristic 对象表⽰示。 图 1-5 阐明了远程外设的基服务和特征的基本结构。

外设⽅方相关对象

⾃自 OS X v10.9 和 iOS 6,Mac 和 iOS 设备(包括Mac,iPhone,iPad)能够提供 BLE 外设功能,给其他设备提供服务数据。设置你的设备充当外设的⾓角⾊色时, 你要完成 BLE 通信中外设那⼀一侧的功能⾏行为。

本地外设和远程主机

在外设⼀一侧,本地外设⽤用 CBPeripheralManager 对象表⽰示。这些对象⽤用来管理发布本地外设服务和特征数据库中的服务,⼲⼴广播到远程主机设备(⽤用 CBCentral 对 象表⽰示)。外设管理对象也⽤用来响应远程主机的读写请求。图 1-6 显⽰示了本地外设和远程主机在 Core Bluetooth 中的表⽰示。

本地外设数据⽤用 CBMutableService 和 CBMutableCharacteristic 对象表⽰示

设置⼀一个本地外设并与它交互数据时,你需要处理本地外设的多个服务和特征的版本。在 Core Bluetooth 框架,本地外设的服务⽤用 CBMutableService 对象表 ⽰示。类似的,本地外设的特征⽤用 CBMuableCharacteristic 对象表⽰示。 图 1-7 阐明了本地外设服务和特征的基本机构。

主机通常要完成的任务

BLE 中扮演主机⾓角⾊色的设备要完成⼤大量通⽤用的任务--例如,发现和连接可以⽤用的外设,探索外设,与外设交互数据。相对⽽而⾔言,扮演外设的⾓角⾊色也需要完成⼀一些 与主机不同的通⽤用的任务,例如发布和⼲⼴广播服务,响应读写数据,处理已连接的主机的请求。
本章将学习如何使⽤用 Core Bluetooth 完成 BLE 主机端的通⽤用任务。基于代码的⽰示例可以帮助你⽤用本地设备扮演主机的⾓角⾊色。具体来说你可以学习到:

  启动主机管理对象
发现和连接⼲⼴广播的外设
连接之后探索外设数据
给外设服务的⼀一些特征值发送读写请求
订阅特征值并在他们更新时得到通知
下⼀一章将会学习如何⽤用本地设备扮演外设⾓角⾊色。
本章的⽰示例代码简单⽽而抽象,在你实际的应⽤用中需要对其做适当的修改来完善。许多跟主机相关的⾼高级主题会再后⾯面的章节讲述。

启动主机管理

CBCentralManager 对象时本地主机设备⾯面向对象的表⽰示,完成 BLE 传输前需要分配和初始化⼀一个主机管理实例。你可以通过调⽤用CBCentralManager类的 initWithDelegate:queue:options: ⽅方法初始化主机管理对象,如下所⽰示:

 myCentralManager =
[[CBCentralManager alloc] initWithDelegate:self queue:nil options:nil];

在这个例⼦子中,self 被设置为接收任何主机事件的委托。通过指定 dispatch queue 为 nil,主机管理对象会⽤用 main queue 主队列分发主机事件。 当你创建⼀一个主机管理对象,它会调⽤用它委托的 centralManagerDidUpdateState: ⽅方法。你需要实现改委托⽅方法确保 BLE 在主机设备上被⽀支持和可⽤用。关于如果 完成该委托⽅方法的更多信息,参⻅见 CBCentralManagerDelegate Protocol Reference。

发现在⼲⼴广播的外设

主机端的第⼀一个任务是发现应⽤用需要连接的可⽤用的外设。正如前⾯面提到的,⼲⼴广播是外设让外界感知它存在的主要⽅方式。你可以通过调⽤用 CBCentralManager 类的 scanForPeripheralsWithServices:options: ⽅方法来发现任何正在⼲⼴广播的外设,如下所⽰示:

[myCentralManager scanForPeripheralsWithServices:nil options:nil];

注意:如果第⼀一个参数填 nil,主机管理对象返回所有发现的外设,⽽而不管他们提供什么服务。在实际的应⽤用中,你需要指定⼀一个 CBUUID 对象的数组,每⼀一个 CBUUID 对象表⽰示⼀一个 UUID,代表外设正在⼲⼴广播的⼀一个服务。当你指定了 UUID 数组,主机管理对象仅返回⼲⼴广播这些服务的外设,可以让你仅扫描你感兴趣的 设备。
在调⽤用 scanForPeripheralsWithServices:options: ⽅方法发现可⽤用的外设后,主机管理对象每发现⼀一个外设都调⽤用⼀一次它的委托⽅方法
centralManager:didDiscoverPeripheral:advertisementData:RSSI: 。任何被发现的外设都返回⼀一个 CBPeripheral 对象。如下⾯面所⽰示,你可以完成该委托⽅方法来列
出发现的任何外设:

-(void)centralManager:(CBCentralManager *)central
didDiscoverPeripheral:(CBPeripheral *)peripheral
advertisementData:(NSDictionary *)advertisementData
RSSI:(NSNumber *)RSSI {
NSLog(@"Discovered %@", peripheral.name);
...
当你发现你想连接的外设后,停⽌止扫描其它设备以节约电量。
[myCentralManager stopScan];
NSLog(@"Scanning stopped");

发现外设后连接它

在你发现你感兴趣的外设后,可以请求连接,通过调⽤用 CBCentralManager 类的 connectPeripheral:options: ⽅方法。简单的调⽤用该⽅方法到你需要连接的指定外设, 如下所⽰示:

[myCentralManager connectPeripheral:peripheral options:nil];

假设连接成功,主机管理对象会调⽤用它的委托⽅方法 centralManager:didConnectPeripheral: ,你可以在建⽴立连接后记录⽇日志,如下所⽰示:

- (void)centralManager:(CBCentralManager *)central
didConnectPeripheral:(CBPeripheral *)peripheral {
NSLog(@"Peripheral connected");
...
在与外设交互之前,需要设置外设的委托以确保期望的回调⽅方法能响应,如下所⽰示:
peripheral.delegate = self;

发现已连接外设的服务

在与外设建⽴立连接之后,你可以探索它的数据。探索外设的数据的第⼀一步是发现它可⽤用的服务。因为⼲⼴广播的数据量⼤大⼩小是有限制的,你需要探索外设的更多服务 ⽽而不仅是⼲⼴广播。你可以调⽤用 CBPeripheral 类的 discoverServices: ⽅方法来发现外设提供的所有服务。

[peripheral discoverServices:nil];

注意:在实际的应⽤用中,你不应该传递 nil 做参数,因为这样会返回外设的所有服务。外设可能会拥有很多服务,⽽而不仅仅是你感兴趣的那些。发现服务会浪费电 池和时间。更多情况下,你应该为你感兴趣的服务指定 UUID。

指定服务被发现时,外设(就是你已经连接上的 CBPeripheral 对象)调⽤用 peripheral:didDiscoverServices: 委托⽅方法。Core Bluetooth 建⽴立⼀一个 CBService 对象 的数组--数组的每⼀一个元素都对应⼀一个外设已发现的服务。如下所⽰示,你可以实现委托⽅方法来访问数组中的服务:

- (void)peripheral:(CBPeripheral *)peripheral
didDiscoverServices:(NSError *)error {
for (CBService *service in peripheral.services) {
NSLog(@"Discovered service %@", service);
... } ...

发现服务的特征

假设你已经发现了你感兴趣的服务,下⼀一步探索就是发现服务提供的所有特征。简单的调⽤用 CBPeripheral 类的 discoverCharacteristics:forService: ⽅方法就可以发 现⼀一个服务的所有特征,对于⼀一个服务来说,可以操作如下所⽰示:

NSLog(@"Discovering characteristics for service %@", interestingService);
[peripheral discoverCharacteristics:nil forService:interestingService];

注意:在实际的应⽤用中,第⼀一个参数不应该传递 nil,因为这样会返回⼀一个外设服务的所有特征。因为外设的⼀一个服务可能包含许多的特征,⽽而不仅仅是你感兴趣 的那些,发现所有特征会影响电池寿命和浪费时间。更多情况下,你应该为你感兴趣的特征指定 UUID。

外设指定服务的特征被发现后会调⽤用它委托对象的 peripheral:didDiscoverCharacteristicsForService:error: ⽅方法。Core Bluetooth 建⽴立⼀一个 CBCharacteristic 对象 的数组--数组的每⼀一个元素都对应⼀一个已发现的特征。下⾯面的例⼦子显⽰示了如何实现委托⽅方法来简单的打印已发现的每⼀一个特征:

- (void)peripheral:(CBPeripheral *)peripheral
didDiscoverCharacteristicsForService:(CBService *)service
error:(NSError *)error {
for (CBCharacteristic *characteristic in service.characteristics) {
NSLog(@"Discovered characteristic %@", characteristic);
... } ...

获取特征的值

特征 包含了简单的值,⽤用来 表⽰示外设服务的更多信息 。例如,健康体温计服务的温度测量特征可能有⼀一个值⽤用来表⽰示摄⽒氏度。你可以直接获取或者订阅这些 值。

读特征值

在你找到你感兴趣的服务的特征后,你可以读取你想要的特征值,通过调⽤用 CBPeripheral 类的 readValueForCharacteristic: ⽅方法,如下所⽰示:

NSLog(@"Reading value for characteristic %@", interestingCharacteristic);
[peripheral readValueForCharacteristic:interestingCharacteristic];

当你尝试读取特征值时,外设调⽤用它委托对象的 peripheral:didUpdateValueForCharacteristic:error: ⽅方法获取值。如果获取成功,可以通过特征值的属性来访问这 些值,如下所⽰示:

- (void)peripheral:(CBPeripheral *)peripheral
didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic
error:(NSError *)error {
NSData *data = characteristic.value;
// parse the data as needed
...

注意 :并⾮非所有的特征都有可读的值。你可以通过访问 CBCharacteristicPropertyRead 来查明特征值是否可读,详情参阅 CBCharacteristic Class Reference。如果你尝试读取⼀一个不可读的值,peripheral:didUpdateValueForCharacteristic:error: 会适当的返回⼀一个错误。

订阅特征值

虽然使⽤用 readValueForCharacteristic: ⽅方法读取特征值能够⾼高效满⾜足⼤大多数应⽤用场景,但它不是最⾼高效的获取值改变的⽅方式。⼤大多数特征值改变的时候--例如,任 意时刻的⼼心率--你应该通过订阅来获取特征值。当你订阅特征值,在值改变的时候,你能够收到外设的通知。
你可以订阅感兴趣的特征值,通过调⽤用 CBPeripheral 类的 setNotifyValue:forCharacteristic: ⽅方法并指定第⼀一个参数为 YES,如下所⽰示:

 [peripheral setNotifyValue:YES forCharacteristic:interestingCharacteristic];

当你尝试订阅(或取消订阅)⼀一个特征值,外设会调⽤用它委托对象的 peripheral:didUpdateNotificationStateForCharacteristic:error: ⽅方法。如果订阅请求失败,你 可以完成该委托来访问失败原因,如下所⽰示:

- (void)peripheral:(CBPeripheral *)peripheral
didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic
error:(NSError *)error {
if (error) {
NSLog(@"Error changing notification state: %@",
[error localizedDescription]);

注意 :并⾮非所有的特征都允许你订阅他们的值。你可以查明⼀一个特征是否配置为可订阅的,通过访问 Characteristic Properties 枚举,详情参阅 CBCharacteristic Class Reference。

在成功订阅特征值之后,在值发⽣生改变的时候外设会给应⽤用发通知。每次值的改变,外设都会调⽤用它委托对象的 peripheral:didUpdateValueForCharacteristic:error: ⽅方法。要获取更新后的值,你需要实现该委托⽅方法。

写特征值

在很多⽤用户场景下,需要⽤用到写特征值。例如,如果你的应⽤用与⼀一个基于 BLE 的数字温度调节器交互,你需要提供⼀一个值让它设定室温。如果特征值是可写的, 你可以给它写⼊入⼀一些数据(NSData类型),通过调⽤用 CBPeripheral 类的 writeValue:forCharacteristic:type: ⽅方法,如下所⽰示:

NSLog(@"Writing value for characteristic %@", interestingCharacteristic); [peripheral writeValue:dataToWrite forCharacterist
ic:interestingCharacteristic
type:CBCharacteristicWriteWithResponse];

当尝试写⼀一个特征值,你需要指定你需要完成的写类型。上⾯面的例⼦子指定的写类型是 CBCharacteristicWriteWithResponse,意味着外设会让你的应⽤用知道写操作 是否成功。Core Bluetooth 框架⽀支持的更多写类型信息,参⻅见 CBPeripheral Class Reference 的枚举 CBCharacteristicWriteType。 如果指定了CBCharacteristicWriteWithResponse,外设通过调⽤用委托对象的peripheral:didWriteValueForCharacteristic:error: ⽅方法来响应⼀一个写请求。如果写失 败,你可以实现该委托⽅方法来获取错误原因,如下所⽰示:

- (void)peripheral:(CBPeripheral *)peripheral
didWriteValueForCharacteristic:(CBCharacteristic *)characteristic
error:(NSError *)error {
if (error) {
NSLog(@"Error writing characteristic value: %@",
[error localizedDescription]);
} ...

意:特征可能仅仅允许特定类型的写操作改变它的值。你可以查明特征值允许哪些写类型,通过访问 Characteristic Properties 的相关属性,详情参考 CBCharacteristic Class Reference。

外设通常要完成的任务

在上⼀一章节,我们学习了如何完成 BLE 主机端的通⽤用任务。在本章,我们学习如何完成 BLE 外设端的通⽤用任务。基于代码的⽰示例可以帮助你⽤用本地设备扮演外 设的⾓角⾊色。具体来说你可以学习到:

  启动外设管理对象
启动外设的服务和特征
发布服务和特征到设备的本地数据库
⼲⼴广播服务
响应已连接的主机的读写请求。
发送更新的特征值给订阅了的主机

你会发现本章的例⼦子很简单和抽象,在你实际的应⽤用中需要对其做适当的修改来完善。在本地设备完成外设功能的许多⾼高级主题--包括提⽰示,陷阱,最佳实践--在 后⾯面的章节中会覆盖到。

启动外设管理

⽤用本地设备扮演外设⾓角⾊色的第⼀一步就是分配和初始化⼀一个外设管理实例(⽤用 CBPeriphralManager 对象表⽰示)。通过 调⽤用 CBPeriphralManager 类的 initWithDelegate:queue:options: ⽅方法启动外设管理,如下所⽰示:

myPeripheralManager =
[[CBPeripheralManager alloc] initWithDelegate:self queue:nil options:nil];

在这个例⼦子中,self 被设置为委托对象来接受外设的事件。当你指定 dispatch queue 为 nil,外设管理对象分发外设事件到主队列。 当你创建⼀一个外设管理者,外设管理者调⽤用 peripheralManagerDidUpdateState: 委托⽅方法。你可以实现该委托⽅方法来确认 BLE 是否在本地外设上可⽤用。更多实现 该委托⽅方法的详情参考 CBPeripheralManagerDelegate Protocol Reference .

设置服务和特征

如图 1-7,本地外设的服务和特征数据库是树形结构。你必须以类似的树形结构来设置服务和特征。完成这些任务的第⼀一步是弄懂服务和特征时如何被定义的

服务和特征⽤用 UUID 标识

外设的服务和特征⽤用128位的 UUID 标识,在 Core Bluetooth 框架中使⽤用 CBUUID 对象。然⽽而不是所有服务和特征的UUID都被蓝⽛牙 Special Interest Group(SIG)预定义出来了。蓝⽛牙 SIG 已经预定义了⼤大量 UUID 为短 16 位以⽅方便使⽤用。例如 ,SIG 已经预定义存储为 16 位的 UUID 180D 标识⼼心率服务。这 个 UUID 等同于 128 位的 UUID:0000180D-0000-1000-8000-00805F9B34FB,预定义在蓝⽛牙 4.0 规范,第 3 卷,3.2.1 节。
CBUUID 类提供了便捷的⼯工⼚厂⽅方法来处理 UUID。例如,在代码中你⽆无须传递⼼心率服务的 128 位 UUID 字符,⽽而是简单的使⽤用 CBUUID 的 UUIDWithString ⽅方
法。如下所⽰示:

CBUUID *heartRateServiceUUID = [CBUUID UUIDWithString: @"180D"];

当你⽤用⼀一个预定义的 16 位 UUID 使⽤用 CBUUID 对象,Core Bluetooth 会填充其余的位。

为⾃自定义的服务和特征创建⾃自定义 UUID

你可以拥有⾮非预定义的服务和特征。前提是你需要⽣生成的你 128 位 UUID 来标识他们。
使⽤用命令⾏行⼯工具的 uuidgen 指令可以很⽅方便的⽣生成 128 位的 UUID。第⼀一步,打开⼀一个终端窗⼝口,下⼀一步,在终端输⼊入 uuidgen,就可以得到⼀一个唯⼀一的 128 位
ASCII 字符串⽤用连字符(-)分隔的,下⾯面是⼀一个⽰示例:

$ uuidgen
71DA3FD1-7E10-41C1-B16F-4430B506CDE7

你可以使⽤用这个 UUID 创建⼀一个 CBUUID 对象,使⽤用 UUIDWithString ⽅方法,如下所⽰示:

CBUUID *myCustomServiceUUID =
[CBUUID UUIDWithString:@"71DA3FD1-7E10-41C1-B16F-4430B506CDE7"];

构建你的服务和特征树

在你拥有⾃自定义的 UUID 后,你可以建⽴立可变的服务和特征,然后把他们像树形结构组织在⼀一起。例如,如果你拥有⼀一个特征的 UUID, 你可以建⽴立⼀一个可变的 特征,通过调⽤用 CBMutableCharacteristic 类的initWithType:properties:value:permissions: ⽅方法,如下所⽰示:

myCharacteristic =
[[CBMutableCharacteristic alloc] initWithType:myCharacteristicUUID
properties:CBCharacteristicPropertyRead
value:myValue permissions:CBAttributePermissionsReadable];

当你创建⼀一个可变的特征,设置它的属性,值,权限。你决定特征的属性和权限,是否特征值是可读写的,连接的主机是否能否订阅特征值。在这个例⼦子中,特 征值被设置为可被主机读的。关于⽀支持可变特征的属性和权限的更多详情请参阅 CBMutableCharacteristic Class Reference 。

注意 :如果你指定特征值,它的值被缓存,属性和权限被设置为可读的。如果你需要特征值可以被写,或者你希望特征所属的已发布服务的⽣生命周期内特征值 可以改变,需要设置值为 nil。遵循这个原则可以确保值⽆无论什么时候外设管理对象收到主机的读写请求,值都能被动态处理。

到⺫⽬目前为⽌止,你已经创建了⼀一个可变的特征,你可以创建⼀一个与特征关联的可变的服务。通过调⽤用 CBMutableService 类的 initWithType:primary: ⽅方法,如下所 ⽰示:

myService = [[CBMutableService alloc] initWithType:myServiceUUID primary:YES];

在该例中,第⼆二个参数设置为 YES,意思是服务是主服务(相对次要服务⽽而⾔言的)。 主服务 描述设备的中主要功能,能被别的服务包含或引⽤用。 次要服务 描 述它引⽤用的另外⼀一个服务的上下⽂文。例如,⼼心率监控器主服务可以暴露⼼心率传感器⼼心率数据,⽽而次要服务可以暴露传感器的电池数据。

创建按服务之后,你可以通过设置服务的特征数组来关联⼀一个特征,如下所⽰示:
myService.characteristics = @[myCharacteristic]; 												

Core BlueTooth官方文档翻译的更多相关文章

  1. Core Foundation 官方文档翻译

      Core Foundation框架中常用的隐含类型: 使用这些隐含类型时需要自己初始化,自己去释放内存.所以需要记住,在初始化的同时在相应位置释放.以防出现内存问题.   1.CFStringRe ...

  2. Core Bluetooth【官方文档翻译】【02】

    1.中心设备和外围设备以及它们在蓝牙通讯中的角色. 在所有的BLE( Bluetooth low energy,下文简称蓝牙4.0 )通讯中都涉及2个主要的角色:中心设备和外围设备.它是基于传统的客户 ...

  3. Core Bluetooth 概述 【官方文档翻译】

    Core Bluetooth 框架在Mac和iOS平台,为配备了低功耗蓝牙无线技术的设备提供了进行通信所需要的类.例如,您的应用程序可以发现,探索,和低功耗的外围设备进行交互,如心率监视器.数字温控器 ...

  4. Salt Stack 官方文档翻译 - 一个想做dba的sa - 博客频道 - CSDN.NET

    OSNIT_百度百科 Salt Stack 官方文档翻译 - 一个想做dba的sa - 博客频道 - CSDN.NET Salt Stack 官方文档翻译 分类: 自动运维 2013-04-02 11 ...

  5. ABP 教程文档 1-1 手把手引进门之 ASP.NET Core & Entity Framework Core(官方教程翻译版 版本3.2.5)

    本文是ABP官方文档翻译版,翻译基于 3.2.5 版本 官方文档分四部分 一. 教程文档 二.ABP 框架 三.zero 模块 四.其他(中文翻译资源) 本篇是第一部分的第一篇. 第一部分分三篇 1- ...

  6. Spring官方文档翻译(1~6章)

    Spring官方文档翻译(1~6章) 转载至 http://blog.csdn.net/tangtong1/article/details/51326887 Spring官方文档.参考中文文档 一.S ...

  7. CALayer---iOS-Apple苹果官方文档翻译之CALayer

    CHENYILONG Blog CALayer---iOS-Apple苹果官方文档翻译之CALayer CALayer /*技术博客http://www.cnblogs.com/ChenYilong/ ...

  8. iOS数据存取---iOS-Apple苹果官方文档翻译

    CHENYILONG Blog iOS数据存取---iOS-Apple苹果官方文档翻译 数据存取/*技术博客http://www.cnblogs.com/ChenYilong/ 新浪微博http:// ...

  9. django 1.8 官方文档翻译:13-12 验证器

    django 1.8 官方文档翻译:13-12 验证器 2015年09月20日 21:36:18 ApacheCN_飞龙 阅读数:639  https://blog.csdn.net/wizardfo ...

随机推荐

  1. 洛谷P3688/uoj#291. [ZJOI2017]树状数组

    传送门(uoj) 传送门(洛谷) 这里是题解以及我的卡常数历程 话说后面那几组数据莫不是lxl出的这么毒 首先不难发现这个东西把查询前缀和变成了查询后缀和,结果就是查了\([l-1,r-1]\)的区间 ...

  2. Tomcat乱码问题

    问题:淇℃伅 [main] org.apache.catalina.startup.VersionLoggerListener.log Server容器启动乱码--tomcat 解决:修改.tomca ...

  3. day2逻辑运算作业详解

    1.day2题目 1.判断下列逻辑语句的True,False. 1)1 > 1 or 3 < 4 or 4 > 5 and 2 > 1 and 9 > 8 or 7 &l ...

  4. IOS 打包提示 No iTunes Connect access for the team

    1.可以在提示页直接点击 Manage Accounts按钮,进去页面后,选择开发者账号点减号删除:(或者在Xcode中直接按command+键进入,选择accounts,选中账号按-键删除) 2.完 ...

  5. MySQL库相关操作

    ========MySQL库相关操作====== 一.系统数据库 information_schema: 虚拟库,不占用磁盘空间,存储的是数据库启动后的一些参数,如用户表信息.列信息.权限信息.字符信 ...

  6. [Android]简略的Android消息机制源码分析

    相关源码 framework/base/core/java/andorid/os/Handler.java framework/base/core/java/andorid/os/Looper.jav ...

  7. 使用Zeppelin时出现sh interpreter not found错误的解决办法(图文详解)

    不多说,直接上干货! 问题详解 http://192.168.80.145:8099/#/notebook/2CSV2VT5S 相关博客是 Zeppelin的入门使用系列之使用Zeppelin运行sh ...

  8. 《四 spring源码》spring的事务注解@Transactional 原理分析

    先了解什么是注解 注解 Jdk1.5新增新技术,注解.很多框架为了简化代码,都会提供有些注解.可以理解为插件,是代码级别的插件,在类的方法上写:@XXX,就是在代码上插入了一个插件. 注解不会也不能影 ...

  9. ThreadLocal(关于struts2的ThreadLocal,实际上Jdk1.2就有了)

    ThreadLocal是通过在不同线程中操作变量的副本,来达到线程安全的目的,是用空间资源换时间资源的方式.今天在看struts2源码的时候,发现ActionContext中,就持有一个静态的Thre ...

  10. jetty启动(server-connector-handle-start-join)

    import java.io.File; import java.io.IOException; import java.util.Map; import javax.servlet.ServletE ...