iOS蓝牙开发:蓝牙的连接和数据的读写

       蓝牙开发说简单也简单,说不简单也有点难,开发人员在首次开发蓝牙前首先需要搞清楚蓝牙开发的概念,还要了解掌握蓝牙开发的一整套流程,这样才能快速上手开发蓝牙。

      蓝牙开发分为两种模式:管理者模式和中心者模式。管理者模式基本很少用到,相当于iPhone手机作为外设,自己创建服务和特性,然后用其他设备连接iPhone手机;中心者模式一般是大部分情况下都会使用的,使用中心者模式开发相当于iPhone手机作为主机,连接蓝牙外设,下面介绍蓝牙开发的例子就是使用的中心者模式来讲解的。

在这里我还是要推荐下我自己建的iOS开发学习群:680565220,群里都是学ios开发的,如果你正在学习ios ,小编欢迎你加入,今天分享的这个案例已经上传到群文件,大家都是软件开发党,不定期分享干货(只有iOS软件开发相关的),包括我自己整理的一份2018最新的iOS进阶资料和高级开发教程

一、关于蓝牙开发的一些重要的理论概念:

1、服务(services):蓝牙外设对外广播的时候一定会有一个服务,有些时候也可以是有多个服务,服务下面包含一些特性,服务可以理解成一个模块的窗口;

2、特征(characteristic):特征存在于服务下面的,一个服务下面可以有多个特征,特征可以理解成具体实现功能的窗口,一般的特性都会有value,也就是特征值,是特征和外界交互的最小单位;

      3、UUID:蓝牙上的唯一标示符,为了区分不同服务和特征,就用UUID来表示。

二、蓝牙连接的主要步骤

     1、创建一个CBCentralManager实例来进行蓝牙管理;

     2、搜索扫描外围设备;

     3、连接外围设备;

     4、获得外围设备的服务;

     5、获得服务的特征;

     6、从外围设备读取数据;

     7、给外围设备发送(写入)数据。

三、蓝牙连接和数据读写的具体步骤

     1、导入苹果系统蓝牙框架

#import

     2、遵循两个蓝牙框架相关的协议

     3、新建两个实例属性,一个特征属性

@property (nonatomic, strong) CBCentralManager *centralManager; //中心管理者

@property (nonatomic, strong) CBPeripheral *peripheral; //连接到的外设

@property (nonatomic, strong) CBCharacteristic *characteristic; //特征

     4、初始化CBCentralManager,进行蓝牙管理

- (void)viewDidLoad {

[super viewDidLoad];

self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()];     //创建实例进行蓝牙管理

}

 //若中心管理者初始化之后 就会触发下面这个代理方法 该代理方法是用来判断手机蓝牙的状态的

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

// 蓝牙可用,开始扫描外设

if (central.state == CBManagerStatePoweredOn) {

NSLog(@"蓝牙可用");

//在中心管理者成功开启之后再进行一些操作

//搜索扫描外设

// 根据SERVICE_UUID来扫描外设,如果不设置SERVICE_UUID,则扫描所有蓝牙设备

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

[central scanForPeripheralsWithServices:nil options:nil];

}

if(central.state == CBManagerStateUnsupported) {

NSLog(@"该设备不支持蓝牙");

}

if (central.state == CBManagerStatePoweredOff) {

NSLog(@"蓝牙已关闭");

}

if (central.state == CBManagerStateUnknown) {

NSLog(@"蓝牙当前状态不明确");

}

if (central.state == CBManagerStateUnauthorized) {

NSLog(@"蓝牙未被授权");

}

}

      5、搜索外围设备

//执行扫描动作之后,如果扫描到外设了,就会自动回调下面的协议方法

/** 发现符合要求的外设,回调 */

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

NSLog(@"%@====",peripheral.name);

//根据外设名字有选择性的筛选连接蓝牙设备

if ([peripheral.name hasPrefix:@"TEAMOSA"]) {

//在这里对外设携带的广播数据进行进一步的处理

if ([self.peripheraNames containsObject:peripheral.name]) {

//如果数组中包含了就不再添加

return;

}

//添加到外设名字数组中

[self.peripheraNames addObject:peripheral.name];

//标记外设,让它的生命周期与控制器的一致

self.peripheral = peripheral;

// 可以根据外设名字来过滤外设

// [central connectPeripheral:peripheral options:nil];

}

// 连接外设

// [central connectPeripheral:peripheral options:nil];

}

    6、连接外围设备

//连接外围设备,中心管理者连接外设成功,如果连接成功就会回调这个协议方法

/** 连接成功 */

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

//连接成功之后,可以进行服务和特性的发现。 停止中心管理设备的扫描动作,要不然在你和已经连接好的外设进行数据沟通时,如果又有一个外设进行广播且符合你的连接条件,那么你的iOS设备也会去连接这个设备(因为iOS BLE4.0是支持一对多连接的),导致数据的混乱。

//停止扫描动作

[self.centralManager stopScan];

// 设置外设的代理

peripheral.delegate = self;

// 根据UUID来寻找服务

// [peripheral discoverServices:@[[CBUUID UUIDWithString:SERVICE_UUID]]];

//外设发现服务,传nil代表不过滤,一次性读出外设的所有服务

[peripheral discoverServices:nil];

NSLog(@"%s, line = %d, %@=连接成功", __FUNCTION__, __LINE__, peripheral.name);

}

//外设连接失败

/** 连接失败的回调 */

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

NSLog(@"%s, line = %d, %@=连接失败", __FUNCTION__, __LINE__, peripheral.name);

}

//丢失连接 掉线

/** 断开连接 */

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

NSLog(@"%s, line = %d, %@=断开连接", __FUNCTION__, __LINE__, peripheral.name);

// 断开连接可以设置重新连接

[central connectPeripheral:peripheral options:nil];

}

    7、获取外围设备服务和特征

/** 发现服务 */

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

// 遍历出外设中所有的服务

for (CBService *service in peripheral.services) {

// NSLog(@"所有的服务:%@",service);

}

// 这里仅有一个服务,所以直接获取

CBService *service = peripheral.services.lastObject;

// 根据UUID寻找服务中的特征

// [peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:CHARACTERISTIC_UUID]] forService:service];

// [peripheral discoverCharacteristics:@[service.UUID] forService:service];

[peripheral discoverCharacteristics:nil forService:service];

}

    8、从外围设备读取数据

// 更新特征的value的时候会调用 (凡是从蓝牙传过来的数据都要经过这个回调,简单的说这个方法就是你拿数据的唯一方法) 你可以判断是否 从外围设备读数据

/** 接收到数据回调 */

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

// if (characteristic == @"你要的特征的UUID或者是你已经找到的特征") {

// //characteristic.value就是你要的数据

// }

if ([peripheral.name hasPrefix:@"TEAMOSA"]){

NSData *data = characteristic.value;

NSString *value = [self hexadecimalString:data];

// NSLog(@"characteristic(读取到的): %@, data : %@, value : %@", characteristic, data, value);

}

// 拿到外设发送过来的数据

// NSData *data = characteristic.value;

// self.textFild.text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

}

    9、向外围设备发送(写入)数据

//这个方法你可以放在button的响应里面,也可以在找到特征的时候就写入,具体看你业务需求怎么用

//[self.peripherale writeValue:_batteryData forCharacteristic:self.characteristic type:CBCharacteristicWriteWithResponse];//第一个参数是已连接的蓝牙设备; 第二个参数是要写入到哪个特征; 第三个参数是通过此响应记录是否成功写入 需要注意的是特征的属性是否支持写数据

/** 写入数据回调 */

- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error {

/*

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

};

打印出特征的权限(characteristic.properties),可以看到有很多种,这是一个NS_OPTIONS的枚举,可以是多个值

常见的又read,write,noitfy,indicate.知道这几个基本够用了,前俩是读写权限,后俩都是通知,俩不同的通知方式

*/

// NSLog(@"%s, line = %d, char.pro = %d", __FUNCTION__, __LINE__, characteristic.properties);

// 此时由于枚举属性是NS_OPTIONS,所以一个枚举可能对应多个类型,所以判断不能用 = ,而应该用包含&

NSLog(@"write value success(写入成功) : %@", characteristic);

}

    10、具体调用给蓝牙外设写入数据方法,这里的例子是以按钮点击事件里面来调用处理

//发送按钮点击事件

- (void)sendClick {

if (!self.characteristic) {

return;

}

_tempValue = [NSString stringWithFormat:@"%.0f", progressView.centigradeDegree];

_timeValue = [NSString stringWithFormat:@"%.0ld", (long)progressView1.timeDegree];

NSString *ttData = [NSString stringWithFormat:@"%@,%@U", _tempValue, _timeValue];

// NSString *aaa = [DataCoverTool coverFromStringToHexStr:ttData];

// 用NSData类型来写入

// NSData *data = [NSKeyedArchiver archivedDataWithRootObject:arry];

NSData *data = [ttData dataUsingEncoding:NSUTF8StringEncoding];

// NSData *data = [self dataWithString:ttData];

// 根据上面的特征self.characteristic来写入数据

[self.peripheral writeValue:data forCharacteristic:self.characteristic type:CBCharacteristicWriteWithResponse];

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,898评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,401评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,058评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,539评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,382评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,319评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,706评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,370评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,664评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,715评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,476评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,326评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,730评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,003评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,275评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,683评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,877评论 2 335

推荐阅读更多精彩内容