IOS 怎么获取外设的ibeacon 广播数据格式AdvData

CocoaChina
当下蓝牙开发可谓是越来越火,不论是智能穿戴的兴起还是蓝牙家具,车联网蓝牙等等,很多同学也会接触到蓝牙的项目,我从事蓝牙开发也有一段时间了,经手了两个项目。废话不多说了,先向大家简单的介绍有关蓝牙开发的知识。蓝牙低能耗 ( BLE ) ,以下介绍的都是围绕 iOS 的框架展开的。蓝牙开发分为中心者模式和管理者模式:1. 常用的(其实 99.99%)就是使用中心者模式作为开发,就是我们手机作为主机,连接蓝牙外设;2. 管理者模式,这个基本用到的比较少,我们手机自己作为外设,自己创建服务和特征,然后有其他的设备连接我们的手机。在做蓝牙开发之前,最好先了解一些概念:服务(services):蓝牙外设对外广播的必定会有一个服务,可能也有多个,服务下面包含着一些特征,服务可以理解成一个模块的窗口;特征(characteristic):存在于服务下面的,一个服务下面也可以存在多个特征,特征可以理解成具体实现功能的窗口,一般特征都会有 value,也就是特征值,特征是与外界交互的最小单位;UUID:可以理解成蓝牙上的唯一标识符(硬件上肯定不是这个意思,但是这样理解便于我们开发),为了区分不同的服务和特征,或者给服务和特征取名字,我们就用 UUID 来代表服务和特征。蓝牙连接可以大致分为以下几个步骤1. 建立一个 Central Manager 实例进行蓝牙管理2. 搜索外围设备3. 连接外围设备4. 获得外围设备的服务5. 获得服务的特征6. 从外围设备读数据7. 给外围设备发送数据其他:提醒首先我们先导入系统的 BLE 的框架#import必须遵守 2 个协议/* 中心管理者 /@property
( nonatomic, strong )
CBCentralManager *cM/* 连接到的外设 /@property
( nonatomic, strong )
CBPeripheral *1. 建立一个 Central Manager 实例进行蓝牙管理- ( CBCentralManager
( !_cmgr )
[ [ CBCentralManager
initWithDelegate:self
queue:nil ] ;
_cM}// 只要中心管理者初始化
就会触发此代理方法
判断手机蓝牙状态 -
( void ) centralManagerDidUpdateState: ( CBCentralManager
* ) central{
( central.state )
NSLog ( @"CBCentralManagerStateUnknown" ) ;
NSLog ( @"CBCentralManagerStateResetting" ) ;
NSLog ( @"CBCentralManagerStateUnsupported" ) ;// 不支持蓝牙
NSLog ( @"CBCentralManagerStateUnauthorized" ) ;
NSLog ( @"CBCentralManagerStatePoweredOff" ) ;// 蓝牙未开启
NSLog ( @"CBCentralManagerStatePoweredOn" ) ;// 蓝牙已开启
在中心管理者成功开启后再进行一些操作
[ self.cMgr
scanForPeripheralsWithServices:nil
通过某些服务筛选外设
options:nil ] ;
dict, 条件
搜索成功之后 , 会调用我们找到外设的代理方法
( void ) centralManager: ( CBCentralManager
* ) central
didDiscoverPeripheral: ( CBPeripheral
* ) peripheral
advertisementData: ( NSDictionary
* ) advertisementData
RSSI: ( NSNumber
// 找到外设
}}2. 搜索外围设备
( 我这里为了举例,采用了自己身边的一个手环 ) //
发现外设后调用的方法 -
( void ) centralManager: ( CBCentralManager
* ) central
中心管理者
didDiscoverPeripheral: ( CBPeripheral
* ) peripheral
advertisementData: ( NSDictionary
* ) advertisementData
外设携带的数据
RSSI: ( NSNumber
外设发出的蓝牙信号强度 {
//NSLog ( @"%s,
%@,peripheral
advertisementData
__FUNCTION__,
peripheral,
advertisementData,
peripheral
advertisementData
kCBAdvDataChannel
kCBAdvDataIsConnectable
kCBAdvDataLocalName
kCBAdvDataManufacturerData
kCBAdvDataServiceUUIDs
kCBAdvDataTxPowerLevel
根据打印结果 , 我们可以得到运动手环它的名字叫
需要对连接到的外设进行过滤
1. 信号强度 ( 40 以上才连接 ,
80 以上连接 )
2. 通过设备名 ( 设备字符串前缀是
在此时我们的过滤规则是 : 有 OBand 前缀并且信号强度大于 35
通过打印 , 我们知道 RSSI 一般是带 - 的
[ peripheral.name
hasPrefix:@"OBand" ]
在此处对我们的
advertisementData ( 外设携带的广播数据 )
进行一些处理
通常通过过滤 , 我们会得到一些外设 , 然后将外设储存到我们的可变数组中 ,
这里由于附近只有 1 个运动手环 ,
所以我们先按 1 个外设进行处理
标记我们的外设 , 让他的生命周期
self.peripheral
发现完之后就是进行连接
[ self.cMgr
connectPeripheral:self.peripheral
options:nil ] ;
NSLog ( @"%s,
__FUNCTION__,
__LINE__ ) ;
}}3. 连接外围设备//
中心管理者连接外设成功 -
( void ) centralManager: ( CBCentralManager
* ) central
中心管理者
didConnectPeripheral: ( CBPeripheral
* ) peripheral
NSLog ( @"%s,
%@= 连接成功 ",
__FUNCTION__,
peripheral.name ) ;
连接成功之后 , 可以进行服务和特征的发现
设置外设的代理
self.peripheral.delegate
外设发现服务 , 传 nil 代表不过滤
这里会触发外设的代理方法
( void ) peripheral: ( CBPeripheral
* ) peripheral
didDiscoverServices: ( NSError
[ self.peripheral
discoverServices:nil ] ;}//
外设连接失败 -
( void ) centralManager: ( CBCentralManager
* ) central
didFailToConnectPeripheral: ( CBPeripheral
* ) peripheral
error: ( NSError
* ) error{
NSLog ( @"%s,
%@= 连接失败 ",
__FUNCTION__,
peripheral.name ) ;}//
丢失连接 -
( void ) centralManager: ( CBCentralManager
* ) central
didDisconnectPeripheral: ( CBPeripheral
* ) peripheral
error: ( NSError
* ) error{
NSLog ( @"%s,
%@= 断开连接 ",
__FUNCTION__,
peripheral.name ) ;}4. 获得外围设备的服务 & 5. 获得服务的特征//
发现外设服务里的特征的时候调用的代理方法 ( 这个是比较重要的方法,你在这里可以通过事先知道 UUID 找到你需要的特征,订阅特征,或者这里写入数据给特征也可以 ) -
( void ) peripheral: ( CBPeripheral
* ) peripheral
didDiscoverCharacteristicsForService: ( CBService
* ) service
error: ( NSError
* ) error{
NSLog ( @"%s,
__FUNCTION__,
__LINE__ ) ;
( CBCharacteristic
service.characteristics )
//NSLog ( @"%s,
__FUNCTION__,
}}6. 从外围设备读数据//
更新特征的 value 的时候会调用
(凡是从蓝牙传过来的数据都要经过这个回调,简单的说这个方法就是你拿数据的唯一方法)
你可以判断是否 -
( void ) peripheral: ( CBPeripheral
* ) peripheral
didUpdateValueForCharacteristic: ( CBCharacteristic
* ) characteristic
error: ( NSError
* ) error{
NSLog ( @"%s,
__FUNCTION__,
__LINE__ ) ;
( characteristic
@" 你要的特征的 UUID 或者是你已经找到的特征 " )
//characteristic.value 就是你要的数据
}}7. 给外围设备发送数据(也就是写入数据到蓝牙)这个方法你可以放在 button 的响应里面,也可以在找到特征的时候就写入,具体看你业务需求怎么用啦 [ self.peripherale
writeValue:_batteryData
forCharacteristic:self.characteristic
type:CBCharacteristicWriteWithResponse ] ;// 第一个参数是已连接的蓝牙设备
;第二个参数是要写入到哪个特征;
第三个参数是通过此响应记录是否成功写入//
需要注意的是特征的属性是否支持写数据 -
( void ) yf_peripheral: ( CBPeripheral
* ) peripheral
didWriteData: ( NSData
forCharacteristic: ( nonnull
CBCharacteristic
* ) characteristic{
NS_OPTIONS ( NSUInteger,
CBCharacteristicProperties )
CBCharacteristicPropertyBroadcast
CBCharacteristicPropertyRead
CBCharacteristicPropertyWriteWithoutResponse
CBCharacteristicPropertyWrite
CBCharacteristicPropertyNotify
CBCharacteristicPropertyIndicate
CBCharacteristicPropertyAuthenticatedSignedWrites
CBCharacteristicPropertyExtendedProperties
CBCharacteristicPropertyNotifyEncryptionRequired
NS_ENUM_AVAILABLE ( NA,
CBCharacteristicPropertyIndicateEncryptionRequired
NS_ENUM_AVAILABLE ( NA,
打印出特征的权限 ( characteristic.properties ) , 可以看到有很多种 , 这是一个 NS_OPTIONS 的枚举 , 可以是多个值
常见的又 read,write,noitfy,indicate. 知道这几个基本够用了 , 前俩是读写权限 , 后俩都是通知 , 俩不同的通知方式
NSLog ( @"%s,
__FUNCTION__,
characteristic.properties ) ;
此时由于枚举属性是 NS_OPTIONS, 所以一个枚举可能对应多个类型 , 所以判断不能用
, 而应该用包含 &}其他:提醒有那么多的特征,我们怎么知道哪些特征是用来读数据的,哪些是用来写入的,哪些是需要订阅之后再读的呢?如果你们硬件工程师事先告诉你了,或者有完成的开发文档,那么就可以直接知道了,否则你就需要自己去查看特征的属性,推介可以使用下第三方的 app —— LightBlue,让你更能清楚的看到你蓝牙里面的服务,特征,特征的属性。其他后续有关文章,我会慢慢整理发出来,有需要的同学可以留下邮箱,我这里有视频教程,我也可以回答相关的问题,有错误的地方可以帮忙指出来呦!
相关标签:
原网页已经由 ZAKER 转码排版
科技频道4小时前
IT之家18小时前
科技频道4小时前
科技频道14小时前
科技频道1小时前
科技频道1小时前
IT之家2小时前
IT之家1小时前
手机中国4小时前
cnBeta56分钟前
IT之家1小时前
中关村在线58分钟前
IT之家2小时前
煎蛋-科技31分钟前
TechWeb50分钟前IOS 怎么获取外设的广播数据AdvData - 蓝牙Bluetooth 技术 - 德州仪器在线技术支持社区
IOS 怎么获取外设的广播数据AdvData
发表于2年前
<input type="hidden" id="hGroupID" value="42"
&p>(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{ &&}&/p>
&p>这个方法中的advertisementData只能抓取到下面的键值&/p>
&p>& & kCBAdvDataIsConnectable = 1;&/p>
&p>& & kCBAdvDataLocalName = SimpleBLEP&/p>
&p>& & kCBAdvDataServiceUUIDs = & & (& & & & FFF0& & );&/p>
&p>& & kCBAdvDataTxPowerLevel = 0;&/p>
&p>&span>simpleBLEPeripheral.c&/span>&span lang=&ZH-CN&>的&/span>&span>&avertData&/span>&span lang=&ZH-CN&>数组的内容&/span>&span lang=&ZH-CN&>,也就是下图报文中的&/span>&span>AdvData&/span>&/p>
&/div>&div style=&clear:&>&/div>" />
IOS 怎么获取外设的广播数据AdvData
此问题尚无答案
All Replies
(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{ &&}
这个方法中的advertisementData只能抓取到下面的键值
& & kCBAdvDataIsConnectable = 1;
& & kCBAdvDataLocalName = SimpleBLEP
& & kCBAdvDataServiceUUIDs = & & (& & & & FFF0& & );
& & kCBAdvDataTxPowerLevel = 0;
simpleBLEPeripheral.c的&avertData数组的内容,也就是下图报文中的AdvData
You have posted to a forum that requires a moderator to approve posts before they are publicly available.
Enjoy it ^_^ :
NSArray *keys = [advertisementData allKeys];& & NSData *dataAmb, *dataO& & for (int i = 0; i & [keys count]; ++i) {&&&&& & id key = [keys objectAtIndex: i];&&&&& & NSString *keyName = (NSString *)&&&&& & NSObject *value = [advertisementData objectForKey: key];&&&&& & if ([value isKindOfClass: [NSArray class]]) {&&&&&&&&& & printf(& & key: %s\n&, [keyName cStringUsingEncoding: NSUTF8StringEncoding]);&&&&&&&&& & NSArray *values = (NSArray *)&&&&&&&&& & for (int j = 0; j & [values count]; ++j) {&&&&&&&&&&&&& & if ([[values objectAtIndex: j] isKindOfClass: [CBUUID class]]) {&&&&&&&&&&&&&&&&& & CBUUID *uuid = [values objectAtIndex: j];&&&&&&&&&&&&&&&&& & NSData *data = uuid.&&&&&&&&&&&&&&&&& & if (j == 0) {&&&&&&&&&&&&&&&&&&&&& & dataObj = uuid.&&&&&&&&&&&&&&&&& & } else {&&&&&&&&&&&&&&&&&&&&& & dataAmb = uuid.&&&&&&&&&&&&&&&&& & }&&&&&&&&&&&&&&&&& & printf(&&&& & uuid(%d):&, j);&&&&&&&&&&&&&&&&& & for (int j = 0; j & data. ++j)&&&&&&&&&&&&&&&&&&&&& & printf(& %02X&, ((UInt8 *) data.bytes)[j]);&&&&&&&&&&&&&&&&& & printf(&\n&);&&&&&&&&&&&&& & } else {&&&&&&&&&&&&&&&&& & const char *valueString = [[value description] cStringUsingEncoding: NSUTF8StringEncoding];&&&&&&&&&&&&&&&&& & printf(&&&& & value(%d): %s\n&, j, valueString);&&&&&&&&&&&&& & }&&&&&&&&& & }&&&&& & } else {&&&&&&&&& & const char *valueString = [[value description] cStringUsingEncoding: NSUTF8StringEncoding];&&&&&&&&& & printf(& & key: %s, value: %s\n&, [keyName cStringUsingEncoding: NSUTF8StringEncoding], valueString);&&&&& & }& & }
You have posted to a forum that requires a moderator to approve posts before they are publicly available.
谢谢,可是得出来得结果是
& &key: kCBAdvDataIsConnectable, value: 1
&& key: kCBAdvDataLocalName, value: SimpleBLEPeripheral
&& key: kCBAdvDataServiceUUIDs
& & & uuid(0): FF F0
&& key: kCBAdvDataTxPowerLevel, value: 0
我想获取得广播数据还是读取不到。。。。
You have posted to a forum that requires a moderator to approve posts before they are publicly available.
对于iOS设备,我是通过kCBAdvDataServiceUUIDs得到广播数据的。
You have posted to a forum that requires a moderator to approve posts before they are publicly available.
Li Zongwu:
我也感觉广播数据应该是在advertisementData中的,可以里面就是没有kCBAdvDataServiceUUIDs这个键值。纠结。。。。不知道是不是那里面的程序不对,你的
-(void)centralManagerDidUpdateState:(CBCentralManager *)central
{....}这里面怎么定义的啊。。。
You have posted to a forum that requires a moderator to approve posts before they are publicly available.
用我之前提供的代码,就可以得到kCBAdvDataServiceUUIDs这个key值,这个key值对应的就是广播里地所谓的数据了。
You have posted to a forum that requires a moderator to approve posts before they are publicly available.
楼主你好,我现在也遇到了同样的问题,请问,后来这个问题你解决了么?哪里可以找到advdata啊?
You have posted to a forum that requires a moderator to approve posts before they are publicly available.
楼上的兄弟,问题解决了吗?我也正在整这个问题。能否共同探讨一下?QQ
You have posted to a forum that requires a moderator to approve posts before they are publicly available.蓝牙(BLE)插件3904人阅读
iOS开发(475)
在写这个博客之前,空余时间抽看了近一个月的文档和Demo,系统给的解释很详细,接口也比较实用,唯独有一点,对于设备的唯一标示,网上众说纷纭,在这里我目前也还没有自己的见解,只是在不断的测试各种情况,亲测同一设备的UUID对于每台iPhone设备都不一样,只能尽量保证设备的唯一性,特别是自动重连的过程,让用户没有感知。我之前也找了很久,发现CBCentralManager和CBPeripheral里边都找不到和Mac地址有关的东西,后来发现一般是外设在Device Information服务中的某个特征返回的。经过与硬件工程师的协商,决定APP端将从这个服务中获取到蓝牙设备以及我的iPhone手机的蓝牙Mac地址,为自动连接的唯一性做准备。
这里经过和硬件工程师的测试,发现设备端在获取手机蓝牙MAC地址的时候,当用户手机重启之后,这个地址也是会随机变化的,也就是说,作为开发者,只有设备的MAC地址能够保持唯一性不变化。
有疑问的朋友可以先去这里瞅一瞅
下面是两台iPhone6连接同一台蓝牙设备的结果:
**成功连接**** peripheral: &CBPeripheral: 0x, identifier = 50084F69-BA5A-34AC-8A6E-6F0CEADB21CD, name = , state = connected& with UUID: &__NSConcreteUUID 0x& 50084F69-BA5A-34AC-8A6E-6F0CEADB21CD**
**成功连接**** peripheral: &CBPeripheral: 0x, identifier = 55B7D759-0F1E-6271-EA14-BC5A9C9EEEEC, name = , state = connected& with UUID: &__NSConcreteUUID 0x& 55B7D759-0F1E-6271-EA14-BC5A9C9EEEEC**
iOS的蓝牙开发很简单,只要包含一个库,创建CBCentralManager实例,实现代理方法,然后就可以直接和设备进行通信。
发现附近的特定蓝牙设备
#import &CoreBluetooth/CoreBluetooth.h&
首先可以定义一些即将使用到的UUID的宏
#define kPeripheralName
@&360qws Electric Bike Service&
#define kServiceUUID
@&7CACEB8B-DFC4-4A40-A942-AAD653D174DC&
#define kCharacteristicUUID @&282A67B2-8DAB-4577-A42F-C4871A3EEC4F&
如果不是把手机作为中心设备的话,这些没有必要设置。
这里我也没有用到,仅仅是提了一下,具体操作后续添加。
对于生成UUID,大家可以谷歌一下,直接通过mac终端生成32位UUID。
1.声明属性
@property (weak, nonatomic) IBOutlet UITableView *bluetoothT
@property (weak, nonatomic) IBOutlet UITextView *resultTextV
@property BOOL cbR
@property(nonatomic) float batteryV
@property (nonatomic, strong) CBCentralManager *
@property (nonatomic, strong) CBPeripheral *
@property (strong ,nonatomic) CBCharacteristic *writeC
@property (strong,nonatomic) NSMutableArray *nD
@property (strong,nonatomic) NSMutableArray *nS
@property (strong,nonatomic) NSMutableArray *nC
2.遵守协议(这里我用到了table)
@interface ViewController () &CBCentralManagerDelegate, CBPeripheralDelegate, UITableViewDataSource, UITableViewDelegate&
3.初始化数据
- (void)viewDidLoad {
[super viewDidLoad];
self.manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
_cbReady = false;
_nDevices = [[NSMutableArray alloc]init];
_nServices = [[NSMutableArray alloc]init];
_nCharacteristics = [[NSMutableArray alloc]init];
_bluetoothTable.delegate = self;
_bluetoothTable.dataSource = self;
count = 0;
4.实现蓝牙的协议方法
(1)检测蓝牙状态
-(void)centralManagerDidUpdateState:(CBCentralManager *)central
switch (central.state) {
case CBCentralManagerStatePoweredOn:
[self updateLog:@&蓝牙已打开,请扫描外设&];
[_activity startAnimating];
[_manager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:@&FF15&]]
options:@{CBCentralManagerScanOptionAllowDuplicatesKey : @YES }];
case CBCentralManagerStatePoweredOff:
[self updateLog:@&蓝牙没有打开,请先打开蓝牙&];
注:[_manager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:@&FF15&]] options:@{CBCentralManagerScanOptionAllowDuplicatesKey : @YES }];中间的@[[CBUUID UUIDWithString:@&FF15&]]是为了过滤掉其他设备,可以搜索特定标示的设备。
(2)检测到外设后,停止扫描,连接设备
-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
[self updateLog:[NSString stringWithFormat:@&已发现 peripheral: %@ rssi: %@, UUID: %@ advertisementData: %@ &, peripheral, RSSI, peripheral.identifier, advertisementData]];
_peripheral =
[_manager connectPeripheral:_peripheral options:nil];
[self.manager stopScan];
[_activity stopAnimating];
BOOL replace = NO;
for (int i=0; i & _nDevices.count; i&#43;&#43;) {
CBPeripheral *p = [_nDevices objectAtIndex:i];
if ([p isEqual:peripheral]) {
[_nDevices replaceObjectAtIndex:i withObject:peripheral];
replace = YES;
if (!replace) {
[_nDevices addObject:peripheral];
[_bluetoothTable reloadData];
(3)连接外设后的处理
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
NSLog(@&%@&, [NSString stringWithFormat:@&成功连接 peripheral: %@ with UUID: %@&,peripheral,peripheral.identifier]);
[self updateLog:[NSString stringWithFormat:@&成功连接 peripheral: %@ with UUID: %@&,peripheral,peripheral.identifier]];
[self.peripheral setDelegate:self];
[self.peripheral discoverServices:nil];
[self updateLog:@&扫描服务&];
-(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
NSLog(@&%@&,error);
-(void)peripheralDidUpdateRSSI:(CBPeripheral *)peripheral error:(NSError *)error
NSLog(@&%s,%@&,__PRETTY_FUNCTION__,peripheral);
int rssi = abs([peripheral.RSSI intValue]);
CGFloat ci = (rssi - 49) / (10 * 4.);
NSString *length = [NSString stringWithFormat:@&发现BLT4.0热点:%@,距离:%.1fm&,_peripheral,pow(10,ci)];
[self updateLog:[NSString stringWithFormat:@&距离:%@&, length]];
(4)发现服务和搜索到的Characteristice
-(void) peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
[self updateLog:@&发现服务.&];
for (CBService *s in peripheral.services) {
[self.nServices addObject:s];
for (CBService *s in peripheral.services) {
[self updateLog:[NSString stringWithFormat:@&%d :服务 UUID: %@(%@)&,i,s.UUID.data,s.UUID]];
i&#43;&#43;;
[peripheral discoverCharacteristics:nil forService:s];
if ([s.UUID isEqual:[CBUUID UUIDWithString:@&FF15&]]) {
BOOL replace = NO;
for (int i=0; i & _nDevices.count; i&#43;&#43;) {
CBPeripheral *p = [_nDevices objectAtIndex:i];
if ([p isEqual:peripheral]) {
[_nDevices replaceObjectAtIndex:i withObject:peripheral];
replace = YES;
if (!replace) {
[_nDevices addObject:peripheral];
[_bluetoothTable reloadData];
-(void) peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
[self updateLog:[NSString stringWithFormat:@&发现特征的服务:%@ (%@)&,service.UUID.data ,service.UUID]];
for (CBCharacteristic *c in service.characteristics) {
[self updateLog:[NSString stringWithFormat:@&特征 UUID: %@ (%@)&,c.UUID.data,c.UUID]];
if ([c.UUID isEqual:[CBUUID UUIDWithString:@&FF01&]]) {
_writeCharacteristic =
if ([c.UUID isEqual:[CBUUID UUIDWithString:@&FF02&]]) {
[_peripheral readValueForCharacteristic:c];
[_peripheral setNotifyValue:YES forCharacteristic:c];
if ([c.UUID isEqual:[CBUUID UUIDWithString:@&FF04&]]) {
[_peripheral readValueForCharacteristic:c];
if ([c.UUID isEqual:[CBUUID UUIDWithString:@&FF05&]]) {
[_peripheral readValueForCharacteristic:c];
[_peripheral setNotifyValue:YES forCharacteristic:c];
if ([c.UUID isEqual:[CBUUID UUIDWithString:@&FFA1&]]) {
[_peripheral readRSSI];
[_nCharacteristics addObject:c];
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
[self updateLog:[NSString stringWithFormat:@&已断开与设备:[%@]的连接&, peripheral.name]];
(5)获取外设发来的数据
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@&FF02&]]) {
NSData * data = characteristic.value;
Byte * resultByte = (Byte *)[data bytes];
for(int i=0;i&[data length];i&#43;&#43;)
printf(&testByteFF02[%d] = %d\n&,i,resultByte[i]);
if (resultByte[1] == 0) {
switch (resultByte[0]) {
if (resultByte[2] == 0) {
[self updateLog:@&撤防成功!!!&];
}else if (resultByte[2] == 1) {
[self updateLog:@&设防成功!!!&];
if (resultByte[2] == 0) {
[self updateLog:@&关坐桶成功!!!&];
}else if (resultByte[2] == 1) {
[self updateLog:@&开坐桶成功!!!&];
if (resultByte[2] == 0) {
[self updateLog:@&解锁电机控制器成功!!!&];
}else if (resultByte[2] == 1) {
[self updateLog:@&锁定电机控制器成功!!!&];
}else if (resultByte[1] == 1) {
[self updateLog:@&未知错误&];
}else if (resultByte[1] == 2) {
[self updateLog:@&鉴权失败&];
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@&FF04&]]) {
NSData * data = characteristic.value;
Byte * resultByte = (Byte *)[data bytes];
for(int i=0;i&[data length];i&#43;&#43;)
printf(&testByteFF04[%d] = %d\n&,i,resultByte[i]);
if (resultByte[0] == 0) {
[self updateLog:@&当前车辆未绑定,请鉴权&];
[self authentication];
[self writePassword:nil newPw:nil];
}else if (resultByte[0] == 1) {
[self updateLog:@&当前车辆已经绑定,请鉴权&];
[self writePassword:nil newPw:nil];
}else if (resultByte[0] == 2) {
[self updateLog:@&当前车辆允许绑定&];
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@&FF05&]]) {
NSData * data = characteristic.value;
Byte * resultByte = (Byte *)[data bytes];
for(int i=0;i&[data length];i&#43;&#43;)
printf(&testByteFF05[%d] = %d\n&,i,resultByte[i]);
if (resultByte[0] == 0) {
[self updateLog:@&当前车辆撤防状态&];
}else if (resultByte[0] == 1) {
[self updateLog:@&当前车辆设防状态&];
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
if (error) {
NSLog(@&Error changing notification state: %@&, error.localizedDescription);
if (characteristic.isNotifying) {
[peripheral readValueForCharacteristic:characteristic];
NSLog(@&Notification stopped on %@.
Disconnecting&, characteristic);
[self updateLog:[NSString stringWithFormat:@&Notification stopped on %@.
Disconnecting&, characteristic]];
[self.manager cancelPeripheralConnection:self.peripheral];
-(void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
if (error) {
NSLog(@&=======%@&,error.userInfo);
[self updateLog:[error.userInfo JSONString]];
NSLog(@&发送数据成功&);
[self updateLog:@&发送数据成功&];
[peripheral readValueForCharacteristic:characteristic];
(6)其他辅助性的
#pragma mark - 蓝牙的相关操作
- (IBAction)bluetoothAction:(UIButton *)sender {
switch (sender.tag) {
[self updateLog:@&正在扫描外设...&];
[_activity startAnimating];
[_manager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:@&FF15&]]
options:@{CBCentralManagerScanOptionAllowDuplicatesKey : @YES }];
double delayInSeconds = 30.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self.manager stopScan];
[_activity stopAnimating];
[self updateLog:@&扫描超时,停止扫描&];
if (_peripheral && _cbReady) {
[_manager connectPeripheral:_peripheral options:nil];
_cbReady = NO;
if (_peripheral && !_cbReady) {
[_manager cancelPeripheralConnection:_peripheral];
_cbReady = YES;
[self.manager stopScan];
[self lock];
[self unLock];
[self open];
[self find];
-(NSOperationQueue *)queue {
if (!_queue) {
self.queue = [[NSOperationQueue alloc]init];
[self.queue setMaxConcurrentOperationCount:1];
#pragma mark - 命令
#pragma mark - 鉴权
-(void)authentication {
Byte byte[] = {1, 1, 2, 3, 4, 5, 6, 7, 8};
if (_peripheral.state == CBPeripheralStateConnected) {
[_peripheral writeValue:[NSData dataWithBytes:byte length:9] forCharacteristic:_writeCharacteristic type:CBCharacteristicWriteWithoutResponse];
#pragma mark - 写密码
-(void)writePassword:(NSString *)initialPw newPw:(NSString *)newPw {
Byte byte[] = {2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8};
if (_peripheral.state == CBPeripheralStateConnected) {
[_peripheral writeValue:[NSData dataWithBytes:byte length:17] forCharacteristic:_writeCharacteristic type:CBCharacteristicWriteWithoutResponse];
#pragma mark - 车辆上锁
-(void)lock {
Byte byte[] = {3, 1};
if (_peripheral.state == CBPeripheralStateConnected) {
[_peripheral writeValue:[NSData dataWithBytes:byte length:2] forCharacteristic:_writeCharacteristic type:CBCharacteristicWriteWithoutResponse];
#pragma mark - 车辆解锁
-(void)unLock {
Byte byte[] = {3, 0};
if (_peripheral.state == CBPeripheralStateConnected) {
[_peripheral writeValue:[NSData dataWithBytes:byte length:2] forCharacteristic:_writeCharacteristic type:CBCharacteristicWriteWithoutResponse];
#pragma mark - 开启坐桶
-(void)open {
Byte byte[] = {4, 1};
if (_peripheral.state == CBPeripheralStateConnected) {
[_peripheral writeValue:[NSData dataWithBytes:byte length:2] forCharacteristic:_writeCharacteristic type:CBCharacteristicWriteWithoutResponse];
#pragma mark - 立即寻车
-(void)find {
Byte byte[] = {7};
if (_peripheral.state == CBPeripheralStateConnected) {
[_peripheral writeValue:[NSData dataWithBytes:byte length:1] forCharacteristic:_writeCharacteristic type:CBCharacteristicWriteWithoutResponse];
-(NSData *)hexString:(NSString *)hexString {
Byte bytes[20];
for(int i=0; i&[hexString length]; i&#43;&#43;)
unichar hex_char1 = [hexString characterAtIndex:i];
int int_ch1;
if(hex_char1 &= '0' && hex_char1 &='9')
int_ch1 = (hex_char1-48)*16;
else if(hex_char1 &= 'A' && hex_char1 &='F')
int_ch1 = (hex_char1-55)*16;
int_ch1 = (hex_char1-87)*16;
i&#43;&#43;;
unichar hex_char2 = [hexString characterAtIndex:i];
int int_ch2;
if(hex_char2 &= '0' && hex_char2 &='9')
int_ch2 = (hex_char2-48);
else if(hex_char1 &= 'A' && hex_char1 &='F')
int_ch2 = hex_char2-55;
int_ch2 = hex_char2-87;
int_ch = int_ch1&#43;int_ch2;
NSLog(@&int_ch=%d&,int_ch);
bytes[j] = int_
j&#43;&#43;;
NSData *newData = [[NSData alloc] initWithBytes:bytes length:20];
return newD
在和硬件之间的数据发送和接受,用的都是byte数组。最后,添加一个存储已连接过得设备
- (void) addSavedDevice:(CFUUIDRef)uuid {
NSArray *storedDevices = [[NSUserDefaults standardUserDefaults] arrayForKey:@&StoredDevices&];
NSMutableArray *newDevices = nil;
CFStringRef uuidString = NULL;
if (![storedDevices isKindOfClass:[NSArray class]]) {
NSLog(@&Can't find/create an array to store the uuid&);
newDevices = [NSMutableArray arrayWithArray:storedDevices];
uuidString = CFUUIDCreateString(NULL, uuid);
if (uuidString) {
[newDevices addObject:(__bridge NSString*)uuidString];
CFRelease(uuidString);
[[NSUserDefaults standardUserDefaults] setObject:newDevices forKey:@&StoredDevices&];
[[NSUserDefaults standardUserDefaults] synchronize];
- (void) loadSavedDevices {
NSArray *storedDevices = [[NSUserDefaults standardUserDefaults] arrayForKey:@&StoredDevices&];
if (![storedDevices isKindOfClass:[NSArray class]]) {
NSLog(@&No stored array to load&);
for (id deviceUUIDString in storedDevices) {
if (![deviceUUIDString isKindOfClass:[NSString class]]) continue;
CFUUIDRef uuid = CFUUIDCreateFromString(NULL, (CFStringRef)deviceUUIDString);
if (!uuid) continue;
[CBCentralManager retrievePeripherals:[NSArray arrayWithObject:(__bridge id)uuid]];
CFRelease(uuid);
- (void) centralManager:(CBCentralManager *)central didRetrieveConnectedPeripherals:(NSArray *)peripherals {
CBPeripheral *
for (peripheral in peripherals) {
[central connectPeripheral:peripheral options:nil];
- (void) centralManager:(CBCentralManager *)central didRetrievePeripheral:(CBPeripheral *)peripheral {
[central connectPeripheral:peripheral options:nil];
最主要是用UUID来确定你要干的事情,特征和服务的UUID都是外设定义好的。我们只需要读取,确定你要读取什么的时候,就去判断UUID是否相符。 一般来说我们使用的iPhone都是做centralManager的,蓝牙模块是peripheral的,所以我们是want datas,需要接受数据。
1.判断状态为powerOn,然后执行扫描
2.停止扫描,连接外设
3.连接成功,寻找服务
4.在服务里寻找特征
5.为特征添加通知
5.通知添加成功,那么就可以实时的读取value[也就是说只要外设发送数据[一般外设的频率为10Hz],代理就会调用此方法]。
6.处理接收到的value,[hex&#20540;,得转换] 之后就自由发挥了,在这期间都是通过代理来实现的,也就是说你只需要处理你想要做的事情,代理会帮你调用方法。[别忘了添加代理]
关于write我这里还有些注意的地方要强调!!!!
并不是每一个Characteristic都可以通过回调函数来查看它写入状态的。就比如针对 immediateAlertService(1802) 的 alertLevelCharacteristic(2A06),就是一个不能有response的Characteristic。刚开始我就一直用CBCharacteristicWriteType.WithResponse来进行写入始终不成功,郁闷坏了,最后看到每个Characteristic还有个属性&#20540;是指示这个的,我将每个Characteristic打印出来有如下信息:
immediateAlertService Discover characteristic &CBCharacteristic: 0x15574d00, UUID = 2A06, properties = 0x4, value = (null), notifying = NO&
linkLossAlertService Discover characteristic &CBCharacteristic: 0x15671d00, UUID = 2A06, properties = 0xA, value = (null), notifying = NO&
这个的properties是什么刚开始不知道,觉得他没意义,后面才注意到properties是Characteristic的一个参数,具体解释如下:
Declaration
struct CBCharacteristicProperties : RawOptionSetType {
init(_ value: UInt)
var value: UInt
static var Broadcast: CBCharacteristicProperties { get }
static var Read: CBCharacteristicProperties { get }
static var WriteWithoutResponse: CBCharacteristicProperties { get }
static var Write: CBCharacteristicProperties { get }
static var Notify: CBCharacteristicProperties { get }
static var Indicate: CBCharacteristicProperties { get }
static var AuthenticatedSignedWrites: CBCharacteristicProperties { get }
static var ExtendedProperties: CBCharacteristicProperties { get }
static var NotifyEncryptionRequired: CBCharacteristicProperties { get }
static var IndicateEncryptionRequired: CBCharacteristicProperties { get }
OBJECTIVE-C
typedef enum {
CBCharacteristicPropertyBroadcast = 0x01,
CBCharacteristicPropertyRead = 0x02,
CBCharacteristicPropertyWriteWithoutResponse = 0x04,
CBCharacteristicPropertyWrite = 0x08,
CBCharacteristicPropertyNotify = 0x10,
CBCharacteristicPropertyIndicate = 0x20,
CBCharacteristicPropertyAuthenticatedSignedWrites = 0x40,
CBCharacteristicPropertyExtendedProperties = 0x80,
CBCharacteristicPropertyNotifyEncryptionRequired = 0x100,
CBCharacteristicPropertyIndicateEncryptionRequired = 0x200,
} CBCharacteristicProperties;
可以看到0x04对应的是CBCharacteristicPropertyWriteWithoutResponse
0x0A对应的是CBCharacteristicPropertyNotify
所以 immediateAlertService(1802) 的 alertLevelCharacteristic(2A06)是不能用CBCharacteristicWriteType.WithRespons进行写入,只能用CBCharacteristicWriteType.WithOutRespons。这样在以后的开发中可以对每个Characteristic的这个参数进行检查再进行设置。
最后讲一下关于蓝牙绑定的过程,在iOS中,没有讲当绑定的过程,直接就是扫描、连接、交互。从而很多人会认为,连接就是绑定了,其实不然。在iOS开发中,连接并没有完成绑定,在网上找到了个很好的解释:
you cannot initiate pairing from the iOS central side. Instead, you have to read/write a characteristic value,
and then let your peripheral respond with an &Insufficient Authentication& error.
iOS will then initiate pairing, will store the keys for later use (bonding) and encrypts the link. As far as I know,
it also caches discovery information, so that future connections can be set up faster.
就是当发生读写交互时,系统在会和外设进行绑定操作!!!
如题,手机作为主设备,在使用CoreBluetooth时候,想获取蓝牙的数据广播包。在使用
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)aPeripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
方法时候获取的advertisementData打印出来只有
** ****kCBAdvDataIsConnectable****kCBAdvDataLocalName****kCBAdvDataManufacturerData**
三个属性对应的&#20540;,但这并非广播包的数据。例如安卓可以通过scandata来获取到广播包的&#20540;,那么iOS这边我应该怎么做呢?
好像苹果这边禁止读取这种广播内容的的,真要的话你可以让硬件那边把数据做到kCBAdvDataManufacturerData这个字段里面。
Demo地址:
进一步交流 QQ群:
文/煜寒了(简书作者)
原文链接:/p/84b5b834b942
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:544905次
积分:6299
积分:6299
排名:第3593名
原创:10篇
转载:494篇
评论:72条
(10)(29)(33)(19)(16)(24)(27)(33)(33)(33)(40)(42)(38)(35)(32)(48)(15)(7)}

我要回帖

更多关于 ble 广播数据格式 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信