一、引言

蓝牙是设备近距离通信的一种方便手段,在iPhone引入蓝牙4.0后,设备之间的通讯变得更加简单。相关的蓝牙操作由专门的 CoreBluetooth.framework进行统一管理。通过蓝牙进行通讯交互分为两方,一方为中心设备central,一方为外设 peripheral,外设通过广播的方式向外发送信息,中心设备检索到外设发的广播信息,可以进行配对连接,进而进行数据交互。

二、中心设备CBCentralManager

CBCentralManager是管理中心设备的管理类,其中重要方法如下:

//设置中心设备代理
@property(assign, nonatomic, nullable) id<CBCentralManagerDelegate> delegate;
//中心设备当前状态
@property(readonly) CBCentralManagerState state;
//中心设备是否正在扫描
@property(readonly) BOOL isScanning NS_AVAILABLE(NA, 9_0);

其中state是一个枚举,有关蓝牙是否可用的状态如下:

typedef NS_ENUM(NSInteger, CBCentralManagerState) {
        //状态未知
CBCentralManagerStateUnknown = 0,
//连接断开 即将重置
CBCentralManagerStateResetting,
//该平台不支持蓝牙
CBCentralManagerStateUnsupported,
//未授权蓝牙使用
CBCentralManagerStateUnauthorized,
//蓝牙关闭
CBCentralManagerStatePoweredOff,
//蓝牙正常开启
CBCentralManagerStatePoweredOn,
};

下面这些方法用于初始化管理中心:

//初始化方法
//设置的代理需要遵守CBCentralManagerDelegate协议
//queue可以设置蓝牙扫描的线程 传入nil则为在主线程中进行
- (instancetype)initWithDelegate:(nullable id<CBCentralManagerDelegate>)delegate
   queue:(nullable dispatch_queue_t)queue;
//此方法同上 在options字典中用于进行一些管理中心的初始化属性设置
//字典中支持的键值如下
/*
NSString * const CBCentralManagerOptionShowPowerAlertKey 对应一个NSNumber类型的bool值,用于设置是否在关闭蓝牙时弹出用户提示
NSString * const CBCentralManagerOptionRestoreIdentifierKey 对应一个NSString对象,设置管理中心的标识符ID
*/
- (instancetype)initWithDelegate:(nullable id<CBCentralManagerDelegate>)delegate
   queue:(nullable dispatch_queue_t)queue
 options:(nullable NSDictionary<NSString *, id> *)options;
//根据获取所有已知设备
- (NSArray<CBPeripheral *> *)retrievePeripheralsWithIdentifiers:(NSArray<NSUUID *> *)identifiers;
//根据服务id获取所有连接的设备
- (NSArray<CBPeripheral *> *)retrieveConnectedPeripheralsWithServices:(NSArray<CBUUID *> *)serviceUUIDs;

在初始化管理中心完成后,会回调代理中的如下方法,我们必须实现如下方法:

//这个方法中可以获取到管理中心的状态
- (void)centralManagerDidUpdateState:(CBCentralManager *)central;

如果上面方法中管理中心状态为蓝牙可用,可以通过下面方法开启扫描外设:

//serviceUUIDs用于扫描一个特点ID的外设 options用于设置一些扫描属性 键值如下
/*
//是否允许重复扫描 对应NSNumber的bool值,默认为NO,会自动去重
NSString *const CBCentralManagerScanOptionAllowDuplicatesKey;
//要扫描的设备UUID 数组 对应NSArray
NSString *const CBCentralManagerScanOptionSolicitedServiceUUIDsKey;
*/
- (void)scanForPeripheralsWithServices:(nullable NSArray<CBUUID *> *)serviceUUIDs options:(nullable NSDictionary<NSString *, id> *)options;
//停止扫描外设
- (void)stopScan;

扫描的结果会在如下代理方法中回掉:

//peripheral 扫描到的外设
//advertisementData是外设发送的广播数据
//RSSI 是信号强度
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *, id> *)advertisementData RSSI:(NSNumber *)RSSI;

扫描到外设后,通过下面方法可以连接一个外设:

/*
options中可以设置一些连接设备的初始属性键值如下
//对应NSNumber的bool值,设置当外设连接后是否弹出一个警告
NSString *const CBConnectPeripheralOptionNotifyOnConnectionKey;
//对应NSNumber的bool值,设置当外设断开连接后是否弹出一个警告
NSString *const CBConnectPeripheralOptionNotifyOnDisconnectionKey;
//对应NSNumber的bool值,设置当外设暂停连接后是否弹出一个警告
NSString *const CBConnectPeripheralOptionNotifyOnNotificationKey;
*/
- (void)connectPeripheral:(CBPeripheral *)peripheral options:(nullable NSDictionary<NSString *, id> *)options;
//取消一个外设的连接
- (void)cancelPeripheralConnection:(CBPeripheral *)peripheral;

调用过连接外设的方法后,会回掉如下代理方法:

//连接外设成功
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral;
//连接外设失败
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error;
//断开外设连接
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error;

当管理中心恢复时会调用如下代理:

//dict中会传入如下键值对
/*
//恢复连接的外设数组
NSString *const CBCentralManagerRestoredStatePeripheralsKey;
//恢复连接的服务UUID数组
NSString *const CBCentralManagerRestoredStateScanServicesKey;
//恢复连接的外设扫描属性字典数组
NSString *const CBCentralManagerRestoredStateScanOptionsKey;
*/
- (void)centralManager:(CBCentralManager *)central willRestoreState:(NSDictionary<NSString *, id> *)dict;

三、外设CBPeripheralManager

从上面我们知道,中心设备是用来扫描周围的外设,两台设备的通讯中,必须有一个充当中心设备,一个充当外设,外设是由CBPeripheralManager进行管理,主要方法如下:

//设置外设管理中心代理
@property(assign, nonatomic, nullable) id<CBPeripheralManagerDelegate> delegate;
//外设状态 枚举如中心设备
@property(readonly) CBPeripheralManagerState state;
//是否正在发送广播
@property(readonly) BOOL isAdvertising;
//用户的授权状态
+ (CBPeripheralManagerAuthorizationStatus)authorizationStatus;
//初始化并设置代理 参数的具体含义与中心设备管理中心
- (instancetype)initWithDelegate:(nullable id<CBPeripheralManagerDelegate>)delegate
   queue:(nullable dispatch_queue_t);
- (instancetype)initWithDelegate:(nullable id<CBPeripheralManagerDelegate>)delegate
   queue:(nullable dispatch_queue_t)queue
 options:(nullable NSDictionary<NSString *, id> *)options;
//开始发送广播
//advertisementData中可以发送的数据有约定 如下
/*
对应设置NSString类型的广播名
NSString *const CBAdvertisementDataLocalNameKey;
外设制造商的NSData数据
NSString *const CBAdvertisementDataManufacturerDataKey;
外设制造商的CBUUID数据
NSString *const CBAdvertisementDataServiceDataKey;
服务的UUID与其对应的服务数据字典数组
NSString *const CBAdvertisementDataServiceUUIDsKey;
附加服务的UUID数组
NSString *const CBAdvertisementDataOverflowServiceUUIDsKey;
外设的发送功率 NSNumber类型
NSString *const CBAdvertisementDataTxPowerLevelKey;
外设是否可以连接
NSString *const CBAdvertisementDataIsConnectable;
服务的UUID数组
NSString *const CBAdvertisementDataSolicitedServiceUUIDsKey;
*/
- (void)startAdvertising:(nullable NSDictionary<NSString *, id> *)advertisementData;
//停止发送广播
- (void)stopAdvertising;
//设置一个连接的具体central设备的延时 枚举如下
/*
typedef NS_ENUM(NSInteger, CBPeripheralManagerConnectionLatency) {
CBPeripheralManagerConnectionLatencyLow = 0,
CBPeripheralManagerConnectionLatencyMedium,
CBPeripheralManagerConnectionLatencyHigh
} NS_ENUM_AVAILABLE(NA, 6_0);
*/
- (void)setDesiredConnectionLatency:(CBPeripheralManagerConnectionLatency)latency forCentral:(CBCentral *)central;
//添加一个服务
- (void)addService:(CBMutableService *)service;
//移除一个服务
- (void)removeService:(CBMutableService *)service;
//移除所有服务
- (void)removeAllServices;
//响应中心设备的读写请求
- (void)respondToRequest:(CBATTRequest *)request withResult:(CBATTError)result;
//更新一个连接中心设备的订阅特征值
- (BOOL)updateValue:(NSData *)value forCharacteristic:(CBMutableCharacteristic *)characteristic onSubscribedCentrals:(nullable NSArray<CBCentral *> *)centrals;

外设代理的相关方法如下:

//这个方法是必须实现的 状态可用后可以发送广播
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral;
//连接回复时调用的方法 和centralManager类似
- (void)peripheralManager:(CBPeripheralManager *)peripheral willRestoreState:(NSDictionary<NSString *, id> *)dict;
//开始发送广播时调用的方法
- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(nullable NSError *)error;
//添加服务调用的回调
- (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(nullable NSError *)error;
//当一个central设备订阅一个特征值时调用的方法
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic;
//取消订阅一个特征值时调用的方法
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic;
//收到读请求时触发的方法
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request;
//收到写请求时触发的方法
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray<CBATTRequest *> *)requests;
//外设准备更新特征值时调用的方法
- (void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral;

四、中心设备与外设对象CBCentral与CBPeripheral

上面介绍了中心设备管理类与外设管理类,这些类用于将设备连接建立起来,器具的数据交换的服务和一些信息则是在对应的设备对象中。

1、中心设备 CBCentral属性与方法

//设备UUID
@property(readonly, nonatomic) NSUUID *identifier;
//中心设备最大接收的数据长度
@property(readonly, nonatomic) NSUInteger maximumUpdateValueLength;

2、外设CAPeripheral属性与方法

外设对象要比中心对象复杂的多,当centralManager连接到外设后,需要通过外设对象的代理方法进行数据交互,其中主要方法属性如下:

//设置代理
@property(assign, nonatomic, nullable) id<CBPeripheralDelegate> delegate;
//外设name
@property(retain, readonly, nullable) NSString *name;
//信号强度
@property(retain, readonly, nullable) NSNumber *RSSI NS_DEPRECATED(NA, NA, 5_0, 8_0);
//外设状态
/*
typedef NS_ENUM(NSInteger, CBPeripheralState) {
CBPeripheralStateDisconnected = 0,//未连接
CBPeripheralStateConnecting,//正在链接
CBPeripheralStateConnected,//已经连接
CBPeripheralStateDisconnecting NS_AVAILABLE(NA, 9_0),//正在断开连接
} NS_AVAILABLE(NA, 7_0);
*/
@property(readonly) CBPeripheralState state;
//所有的服务数组
@property(retain, readonly, nullable) NSArray<CBService *> *services;
//获取当前信号强度
- (void)readRSSI;
//根据服务UUID寻找服务对象
- (void)discoverServices:(nullable NSArray<CBUUID *> *)serviceUUIDs;
//在服务对象UUID数组中寻找特定服务
- (void)discoverIncludedServices:(nullable NSArray<CBUUID *> *)includedServiceUUIDs forService:(CBService *)service;
//在一个服务中寻找特征值
- (void)discoverCharacteristics:(nullable NSArray<CBUUID *> *)characteristicUUIDs forService:(CBService *)service;
//从一个特征中读取数据
- (void)readValueForCharacteristic:(CBCharacteristic *)characteristic;
//写数据的最大长度
//type枚举如下
/*
typedef NS_ENUM(NSInteger, CBCharacteristicWriteType) {
CBCharacteristicWriteWithResponse = 0,//写数据并且接收成功与否回执
CBCharacteristicWriteWithoutResponse,//写数据不接收回执
};
*/
- (NSUInteger)maximumWriteValueLengthForType:(CBCharacteristicWriteType)type NS_AVAILABLE(NA, 9_0);
//向某个特征中写数据
- (void)writeValue:(NSData *)data forCharacteristic:(CBCharacteristic *)characteristic type:(CBCharacteristicWriteType)type;
//为制定的特征值设置监听通知
- (void)setNotifyValue:(BOOL)enabled forCharacteristic:(CBCharacteristic *)characteristic;
//寻找特征值的描述
- (void)discoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic;
//读取特征的描述值
- (void)readValueForDescriptor:(CBDescriptor *)descriptor;
//写特征的描述值
- (void)writeValue:(NSData *)data forDescriptor:(CBDescriptor *)descriptor;

外设的代理方法如下:

//外设名称更改时回调的方法
- (void)peripheralDidUpdateName:(CBPeripheral *)peripheral NS_AVAILABLE(NA, 6_0);
//外设服务变化时回调的方法
- (void)peripheral:(CBPeripheral *)peripheral didModifyServices:(NSArray<CBService *> *)invalidatedServices NS_AVAILABLE(NA, 7_0);
//信号强度改变时调用的方法
- (void)peripheralDidUpdateRSSI:(CBPeripheral *)peripheral error:(nullable NSError *)error NS_DEPRECATED(NA, NA, 5_0, 8_0);
//读取信号强度回调的方法
- (void)peripheral:(CBPeripheral *)peripheral didReadRSSI:(NSNumber *)RSSI error:(nullable NSError *)error NS_AVAILABLE(NA, 8_0);
//发现服务时调用的方法
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(nullable NSError *)error;
//在服务中发现子服务回调的方法
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverIncludedServicesForService:(CBService *)service error:(nullable NSError *)error;
//发现服务的特征值后回调的方法
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(nullable NSError *)error;
//特征值更新时回调的方法
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error;
//向特征值写数据时回调的方法
 - (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error;
 //特征值的通知设置改变时触发的方法
 - (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error;
 //发现特征值的描述信息触发的方法
 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error;
 //特征的描述值更新时触发的方法
 - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForDescriptor:(CBDescriptor *)descriptor error:(nullable NSError *)error;
 //写描述信息时触发的方法
 - (void)peripheral:(CBPeripheral *)peripheral didWriteValueForDescriptor:(CBDescriptor *)descriptor error:(nullable NSError *)error;

五、服务对象CBService

服务对象是用来管理外设提供的一些数据服务的,其中属性如下:

//对应的外设
@property(assign, readonly, nonatomic) CBPeripheral *peripheral;
//是否是初等服务
@property(readonly, nonatomic) BOOL isPrimary;
//包含的自服务
@property(retain, readonly, nullable) NSArray<CBService *> *includedServices;
//服务中的特征值
@property(retain, readonly, nullable) NSArray<CBCharacteristic *> *characteristics;

六、服务的特征值CBCharacteristic

通过绑定服务中的特征值来进行数据的读写操作,其中属性如下:

//对应的服务对象
@property(assign, readonly, nonatomic) CBService *service;
//特征值的属性 枚举如下
/*
typedef NS_OPTIONS(NSUInteger, CBCharacteristicProperties) {
CBCharacteristicPropertyBroadcast,//允许广播特征
CBCharacteristicPropertyRead,//可读属性
CBCharacteristicPropertyWriteWithoutResponse,//可写并且接收回执
CBCharacteristicPropertyWrite,//可写属性
CBCharacteristicPropertyNotify,//可通知属性
CBCharacteristicPropertyIndicate,//可展现的特征值
CBCharacteristicPropertyAuthenticatedSignedWrites,//允许签名的特征值写入
CBCharacteristicPropertyExtendedProperties,
CBCharacteristicPropertyNotifyEncryptionRequired,
CBCharacteristicPropertyIndicateEncryptionRequired
};
*/
@property(readonly, nonatomic) CBCharacteristicProperties properties;
//特征值的数据
@property(retain, readonly, nullable) NSData *value;
//特征值的描述
@property(retain, readonly, nullable) NSArray<CBDescriptor *> *descriptors;
//是否是当前广播的特征
@property(readonly) BOOL isBroadcasted;
//是否是正在通知的特征
@property(readonly) BOOL isNotifying;

七、读写请求对象CBATTRequest

服务对象是外设向中心设备提供的相关数据服务,获取到相应服务后,中心设备可以进行读写请求,读写对象属性如下:

//对应的中心设备
@property(readonly, nonatomic) CBCentral *central;
//对应的特征值
@property(readonly, nonatomic) CBCharacteristic *characteristic;
//读写数据值
@property(readwrite, copy, nullable) NSData *value;

iOS开发之蓝牙通信的更多相关文章

  1. iOS开发之蓝牙通讯

    iOS开发之蓝牙通讯 一.引言 蓝牙是设备近距离通信的一种方便手段,在iPhone引入蓝牙4.0后,设备之间的通讯变得更加简单.相关的蓝牙操作由专门的CoreBluetooth.framework进行 ...

  2. iOS开发之--蓝牙开发实战

    转载自:http://www.cnblogs.com/zyjzyj/p/6029968.html ,感谢英杰 前言 最近一直在开发关于蓝牙的功能,本来是不想写这一篇文章,因为网上关于ios蓝牙开发的文 ...

  3. iOS开发之蓝牙

    // //  ViewController.m //  13-蓝牙 // //  Created by hongqiangli on 2017/7/21. //  Copyright © 李洪强. A ...

  4. iOS开发之蓝牙业务封装

    因为公司做智能家居开发,有很多蓝牙的智能硬件.因此项目中经常需要和蓝牙打交道.为此为了提高开发效率,就把蓝牙的公共业务进行了封装. 本文将对封装的思路做一个简单的阐述. 首先我们需要一个头文件.在这个 ...

  5. iOS开发之蓝牙使用-建立连接的

    1.大佬笔记 CSDN 2.代码 github

  6. iOS开发系列--通讯录、蓝牙、内购、GameCenter、iCloud、Passbook系统服务开发汇总

    --系统应用与系统服务 iOS开发过程中有时候难免会使用iOS内置的一些应用软件和服务,例如QQ通讯录.微信电话本会使用iOS的通讯录,一些第三方软件会在应用内发送短信等.今天将和大家一起学习如何使用 ...

  7. iOS开发——高级技术&蓝牙服务

    蓝牙服务 蓝牙 随着蓝牙低功耗技术BLE(Bluetooth Low Energy)的发展,蓝牙技术正在一步步成熟,如今的大部分移动设备都配备有蓝牙4.0,相比之前的蓝牙技术耗电量大大降低.从iOS的 ...

  8. iOS开发系列通讯录、蓝牙、内购、GameCenter、iCloud、Passbook系统服务开

    --系统应用与系统服务 iOS开发过程中有时候难免会使用iOS内置的一些应用软件和服务,例如QQ通讯录.微信电话本会使用iOS的通讯录,一些第三方软件会在应用内发送短信等.今天将和大家一起学习如何使用 ...

  9. iOS开发系列--通讯录、蓝牙、

    iOS开发过程中有时候难免会使用iOS内置的一些应用软件和服务,例如QQ通讯录.微信电话本会使用iOS的通讯录,一些第三方软件会在应用内发送短信等.今天将和大家一起学习如何使用系统应用.使用系统服务: ...

随机推荐

  1. SPRING IN ACTION 第4版笔记-第四章ASPECT-ORIENTED SPRING-009-带参数的ADVICE2

    一. 情景:有个魔术师会读心术,常人一想一事物他就能读到.以魔术师为切面织入常人的内心. 二. 1. // <start id="mindreader_java" /> ...

  2. Spring AOP实现方式四之注入式AspectJ切面【附源码】

    现在我们要讲的是第四种AOP实现之注入式AspectJ切面 通过简单的配置就可以实现AOP了. 源码结构: 1.首先我们新建一个接口,love 谈恋爱接口. package com.spring.ao ...

  3. [转] Manacher算法详解

    转载自: http://blog.csdn.net/dyx404514/article/details/42061017 Manacher算法 算法总结第三弹 manacher算法,前面讲了两个字符串 ...

  4. apache开源项目--hadoop

    Hadoop 是一个分布式系统基础架构,由Apache基金会开发.用户可以在不了解分布式底层细节的情况下,开发分布式程序.充分利用集群的威力高速运算和存储.Hadoop实现了一个分布式文件系统(Had ...

  5. javascript 中concat与push的区别

    1. push 遇到数组参数时,把整个数组参数作为一个元素:而 concat 则是拆开数组参数,一个元素一个元素地加进去. 2. push 直接改变当前数组:concat 不改变当前数组. 总结:如果 ...

  6. 两种应该掌握的排序方法--------2.quick Sort

    介绍 http://zh.wikipedia.org/wiki/%E5%BF%AB%E9%80%9F%E6%8E%92%E5%BA%8F 用些里面的c++ 实现,感觉这个空间复杂度比较小.还挺好 in ...

  7. import project后,出现Unable to get system library for the project

    import project 后,出现Unable to get system library for the project. 这是因为在import 一个项目的时候,没有指定android sdk ...

  8. remove all event handlers from a control

    The sample code below will remove all Click events from button1 public partial class Form1 : Form { ...

  9. HDU-1026 Ignatius and the Princess I(BFS) 带路径的广搜

      此题需要时间更少,控制时间很要,这个题目要多多看, Ignatius and the Princess I Time Limit: 2000/1000 MS (Java/Others)    Me ...

  10. jps 显示process information unavailable解决方法

    jps 显示process information unavailable解决办法jps时出现如下信息: 4791 -- process information unavailable 解决办法: 进 ...