iOS蓝牙开发CoreBluetooth快速入门
在iOS开发中,实现蓝牙通信有两种方式,一种是使用传统的GameKit.framework,另一种就是使用在iOS 5中加入的CoreBluetooth.framework。
利用CoreBluetooth框架,我们可以轻松实现两个iOS设备、iOS设备与非iOS蓝牙设备的交互。要注意的一点是目前这个框架只能支持蓝牙4.0BLE标准,所以对硬件上是有一定要求的,iPhone 4S及以后的设备,第三代iPad及以后的设备是支持这一标准的。
术语解释
我们首先看一下CoreBluetooth框架的结构。这是CoreBluetooth/CoreBluetooth.h文件中的声明。
1
2
3
4
|
#ifndef _CORE_BLUETOOTH_H_ #define _CORE_BLUETOOTH_H_ #endif #import #import #import #import #import #import #import #import #import #import #import |
其中,CBCentral开头的都是中心设备类,CBPeripheral开头的都是外设类。这就要讲到蓝牙设备的两个角色了。
中心设备:中心设备可以理解为是处理数据的iOS设备,比如你的 iPhone、iPad 等。
外设:外设顾名思义,就是产生数据的外部设备。这个外部设备可以是单片机、嵌入式设备甚至是另一个iOS设备等等。外设可以通过其传感器等产生有用数据,数据后通过蓝牙传给中心设备使用。
在建立连接的之前,外设向外发出广播数据(advertisementData,官方描述“A dictionary containing any advertisement and scan response data.”),广播数据是一个字典类数据,中心设备可以获取一定范围内的外设发出的广播数据。
现在开始
初始化
为了使用CoreBluetooth框架中的回调方法,我们要使用CBCentralManagerDelegate、CBPeripheralDelegate这两个协议。
我们先要初始化一个CBCentralManager类的对象。代码如下:
1
2
3
4
5
6
7
|
@interface SKBluetoothManager : NSObject{ CBCentralManager *manager; id delegate; } manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil]; manager.delegate = self; |
扫描外设
初始化完成,我们就可以让管理器开始扫描外设了:
1
|
[manager scanForPeripheralsWithServices:nil options:nil]; |
在设备发现周围外设的advertisementData后,会回调这个方法:
1
|
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI; |
其中参数central指回调这个方法的中心设备,peripheral指发现的外设对象CBPeripheral,advertisementData就是前面说的字典类型广播数据,RSSI是当前外设的信号强度,单位是dbm。
刚开始对陌生的蓝牙设备调试时,建议我们先用一个数组NSArray将所扫描到的外设进行保存:
1
|
[_peripherals addObject:peripheral]; |
连接外设
保存后,可根据设备的UUID来确定该设备是否为我们需要进行操作的蓝牙设备,在确认外设身份后,即可发起对外设的连接操作:
1
2
3
4
5
6
|
if ([peripheral.identifier.UUIDString isEqualToString:kPeripheralUUID]) { [manager stopScan]; [manager connectPeripheral:peripheral options:nil]; NSLog(@ "连接外设:%@" ,peripheral.description); self.peripheral = peripheral; } |
在此步操作后,我们完成了对蓝牙设备的扫描工作,接下来的回调方法分为两种情况:
连接到外设后
1
2
3
4
5
6
|
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{ NSLog(@ "已经连接到:%@" , peripheral.description); peripheral.delegate = self; [central stopScan]; [peripheral discoverServices:nil]; } |
一旦连接好外设,我们就可以马上停止扫描。然后发起对服务的搜索:
1
|
- (void)discoverServices:(NSArray *)serviceUUIDs; |
此处参数位需要扫描的服务的UUID的数组。文档中特别提到,若该参数为nil,将会扫描所有的服务。
连接失败后
在连接外设失败的回调方法中,提供了error参数,可根据实际需要来做异常处理,在此不做过多说明
1
2
3
|
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { NSLog(@ "连接%@失败" ,peripheral); } |
在搜索到蓝牙设备的服务后,将会回调
1
|
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error |
若有错误发生,通过NSError异常处理。
扫描服务
由于服务在peripheral里是以NSArray的形式存在的,所以我们要对peripheral中的所有服务进行遍历:
1
2
3
4
5
6
7
8
|
for (CBService *service in peripheral.services) { //发现服务 if ([service.UUID isEqual:[CBUUID UUIDWithString:kServiceUUID]]) { NSLog(@ "发现服务:%@" , service.UUID); [peripheral discoverCharacteristics:nil forService:service]; break ; } } |
扫描特征值
在遍历中,趁热打铁,直接对其特征值进行扫描,
1
|
[peripheral discoverCharacteristics:nil forService:service]; |
这里与扫描service是相同的,若扫描所有的特征值,直接传入nil作为参数即可。
这里的kServiceUUID是我们根据蓝牙设备的具体情况,提前设置好的UUID常量。本文所有kXxxxxUUID均为预设的UUID常量。
同样的,characteristics也是一个数组,我们利用像遍历services一样的方式来遍历所有的特征值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error { if (error) { NSLog(@ "搜索特征%@时发生错误:%@" , service.UUID, [error localizedDescription]); return ; } NSLog(@ "服务:%@" ,service.UUID); for (CBCharacteristic *characteristic in service.characteristics) { // NSLog(@"特征:%@",characteristic); //发现特征 if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kCharacteristicWriteUUID]]) { _writeCharacteristic = characteristic; } if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kCharacteristicNotifyUUID]]) { NSLog(@ "监听特征:%@" ,characteristic); //监听特征 [self.peripheral setNotifyValue:YES forCharacteristic:characteristic]; _isConnected = YES; } } } |
特别要提到的是,我们不同的蓝牙设备有不同的服务和特征值。我的蓝牙模块的说明文档中已经说清楚了,write特征、read特征、notify特征,所以在此根据自身需要,来对不同的特征值进行操作。
设置监听
我在此要解释一下,当我们试图去读取蓝牙外设发过来的数据时,一定要找准特征值,用这个方法进行订阅。每次特征值变化的时候,就会有回调方法执行,从而达到读取数据的目的。容易出错误,一定分清楚到底哪个特征值该被订阅。
在订阅了特征值后,我们尝试用蓝牙外设发送一些数据出来,即可回调下一阶段的方法:
1
2
3
4
5
6
7
8
9
|
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { if (error) { NSLog(@ "更新特征值%@时发生错误:%@" , characteristic.UUID, [error localizedDescription]); return ; } // 收到数据 [delegate didGetDataForString:[self hexadecimalString:characteristic.value]]; // NSLog(@"%@",[self hexadecimalString:characteristic.value]); } |
数据的转换
我们接收到的数据,正是characteristic.value,这是一个NSData类数据,我们可以通过UTF8StringEncoding来转化为NSString,为了代码结构清晰,我专门把NSData和NSString互转写成了两个方法:
1
2
3
4
5
6
7
8
9
10
|
//将传入的NSData类型转换成NSString并返回 - (NSString*)hexadecimalString:(NSData *)data{ NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; return result; } //将传入的NSString类型转换成NSData并返回 - (NSData*)dataWithHexstring:(NSString *)hexstring{ NSData *aData; return aData = [hexstring dataUsingEncoding: NSASCIIStringEncoding]; } |
在拿到字符串后,通过各种回调方法,处理UI变动。
封装的 SKBluetooth 的地址:SKBluetooth
iOS蓝牙开发CoreBluetooth快速入门的更多相关文章
- iOS蓝牙开发(二)蓝牙相关基础知识
原文链接: http://liuyanwei.jumppo.com/2015/07/17/ios-BLE-1.html iOS蓝牙开发(一)蓝牙相关基础知识: 蓝牙常见名称和缩写 MFI ====== ...
- iOS 蓝牙开发资料记录
一.蓝牙基础认识: 1.iOS蓝牙开发: iOS蓝牙开发:蓝牙连接和数据读写 iOS蓝牙后台运行 iOS关于app连接已配对设备的问题(ancs协议的锅) iOS蓝牙空中 ...
- iOS之蓝牙开发—CoreBluetooth详解
CoreBluetooth的API是基于BLE4.0的标准的.这个框架涵盖了BLE标准的所有细节.仅仅只有新的iOS设备和Mac是和BLE标准兼容.在CoreBluetooth框架中,有两个主要的角色 ...
- iOS蓝牙开发(4.0)详解
最近由于项目需要, 一直在研究蓝牙4.0,在这儿分享给大家, 望共同进步. 一.关于蓝牙开发的一些重要的理论概念: 1.当前ios中开发蓝牙所运用的系统库是<CoreBluetooth/Core ...
- iOS 蓝牙开发详解
目前iOS智能硬件的开发交互方式主要分为两种,一种是基于低功耗的蓝牙4.0技术(由于耗电低,也称作为BLE(Bluetooth Low Energy))对应iOS的框架为CoreBluetooth,另 ...
- iOS蓝牙开发总结-4
蓝牙开发总结 只要熟悉蓝牙的流程,和蓝牙中每一个角色的作用,其实蓝牙通讯并没有想象中的难 1.蓝牙中心CBCentralManager:一般指得是iPhone手机 2.设备(外设)CBPeripher ...
- iOS蓝牙开发
蓝牙常见名称和缩写 MFI ======= make for ipad ,iphone, itouch 专们为苹果设备制作的设备 BLE ==== buletouch low energy,蓝牙4.0 ...
- ios蓝牙开发(三)ios连接外设的代码实现:手机app去读写蓝牙设备。
手机app去读写蓝牙设备....... 代码下载: 原文博客主提供Github代码连接,地址是:https://github.com/coolnameismy/demo ios连接外设的代码实现流程: ...
- iOS 蓝牙开发(二)iOS 连接外设的代码实现(转)
转载自:http://www.cocoachina.com/ios/20150917/13456.html 原文作者:刘彦玮 上一篇文章介 绍了蓝牙的技术知识,这里我们具体说明一下中心模式的应用场景. ...
随机推荐
- hbase集群的启动,注意几个问题
1.hbase的改的会影响器他的组件的使用, 故而, 在修改 hadoop的任何组件后, 一定要记得其它的组件也能受到影响, 一下是我在将hadoop的集群改了之后 , 再次运行hbase的时候, 就 ...
- sqlserver索引小结
1.1 什么是索引? SQL索引有两种,聚集索引和非聚集索引,索引主要目的是提高了SQL Server系统的性能,加快数据的查询速度与减少系统的响应时间 下面举两个简单的例子: 图书馆的例子:一个图书 ...
- virtaulbox视图模式常用切换
virtaulbox发现菜单不见,如何切换视图模式呢? 很简单,通过快捷键主机(host)键 Host+F 换到全屏模 ...
- 2.goldengate日常维护命令(转载)
goldengate日常维护命令 发表于 2013 年 7 月 4 日 由 Asysdba 1.查看进程状态 GGSCI (PONY) 2> info all 2.查看进程详细状态,有助于排错 ...
- sql对于between和时间
在写时间条件 ,比如 把2014/3/1 到2014/3/31这个时间段做为条件 的话,很多人都会写成这样 select date from table where date between '201 ...
- Android 框架练成 教你打造高效的图片加载框架(转)
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/41874561,本文出自:[张鸿洋的博客] 1.概述 优秀的图片加载框架不要太多, ...
- 常见开发需求之js处理url汉字编码中的乱码
需求及解决 两个页面传值的需求是很常见的,angular中有很多常见的方法用于传值,而且都不会受到字符编码的影响,而采用传统的url中拼字符串进行传值的操作,如果拼串中涉及到中文字符,我们就要考 ...
- 关于DOM的一些操作 整理 积累
var chils= s.childNodes; //得到s的全部子节点 var par=s.parentNode; //得到s的父节点 var ns=s.nextSbiling; //获得 ...
- 《Invert》开发日志05:终止
今天终于看了久闻大名的<独立游戏大电影>,然后我就做了一个坑爹的决定:终止“Invert”项目的开发.没错,在还没正式开工之前,我就决定停掉这个项目,而且是永久终止.做这个决定并不是因为觉 ...
- BZOJ2087 : [Poi2010]Sheep
一条边能连上当且仅当它没有经过任何点,并且两边的点都是偶数个. 枚举原点,通过极角排序求出哪些边是合法的,然后区间DP即可. 时间复杂度$O(nm\log m+n^3)$. #include<c ...