基本流程

1.将手机作为调试机,用来搜索附近的蓝牙设备(在本次练习中,指小米手环)并连接。所以,手机是中央设备central。

2.调试机先扫描周边蓝牙设备,用UITableview展示所扫描到的周边蓝牙设备。

3.将扫描到的蓝牙设备(小米手环)设置为蓝牙发射器,即是周边设备peripheral,进行连接connect。

4.连接上蓝牙设备(小米手环)后,获取蓝牙设备(小米手环)中的所有服务services。

5.对每一个服务service进行遍历,获取其中所有的特性characteristic。

6.读取每一个特性,获取每个特性的值value。

7.对蓝牙设备(小米手环)的指定服务中的指定特性写入数据,实现我们想要达到的效果。

1.扫描设备

新建一个project,我在最开始的ViewController中添加了一个UIButton,title为@“扫描蓝牙”,点击这个按钮会跳到下一个界面BLEViewController,在这个界面中开始扫描附近的蓝牙设备。

首先在BLEViewController中导入蓝牙框架头文件

#import <CoreBluetooth/CoreBluetooth.h>

遵守蓝牙协议

@interfaceBLEViewController ()<CBCentralManagerDelegate>

定义需要用到的属性

/**

*  用于管理中央设备的manager

*/

@property (nonatomic,strong)CBCentralManager *centralManager;

/**

* 用于保存扫描出来的周边设备的数组

*/

@property (nonatomic,strong)NSMutableArray *arrayBLE;

/**

* 用于处理蓝牙事件的线程

*/

@property (nonatomic)dispatch_queue_t bleGCD;

在viewDidLoad方法中进行相关的初始化操作。

//初始化周边设备数组

self.arrayBLE = [[NSMutableArray alloc]init];

//初始化蓝牙线程

self.bleGCD =dispatch_queue_create("BLEgcd",NULL);

//初始化中央设备管理者

self.centralManager = [[CBCentralManager alloc]initWithDelegate:self queue:self.bleGCD];

实现CBCentralManagerDelegate中的代理方法centralManagerDidUpdateState,该方法会监听centralManager的状态变化,当运行程序的设备处在蓝牙开启状态下才开始扫描附近的蓝牙设备。

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

switch (central.state)

{

caseCBCentralManagerStatePoweredOn:

//当前运行程序的设备处于蓝牙开启状态,开始扫描附近的蓝牙设备

[self.centralManager scanForPeripheralsWithServices:niloptions:nil];

break;

default:

NSLog(@"central Manager Did change State");

break;

}

}

- (void)scanForPeripheralsWithServices:(nullableNSArray<CBUUID *> *)serviceUUIDs options:(nullableNSDictionary<NSString *,id> *)options;这个方法会一直不停地调用,在这个方法中,services参数可以传入包含CBUUID的数组,以便只扫描到拥有指定service的蓝牙设备;options参数可以传入包含CBCentralManagerScanOptionAllowDuplicatesKey或

CBCentralManagerScanOptionSolicitedServiceUUIDsKey的字典,前一个键表示是否过滤每次扫描中发现的同一蓝牙设备,后一个键对应的值可以是一个包含CBUUID的数组,以便只扫描指定service,我感觉似乎和本方法第一个参数services有点重复?这里想扫描到附近的所有蓝牙设备,所以都传入nil。

开始扫描之后,当扫描到蓝牙设备时,会来到下面这个方法。

-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI{

BLEinfo * discoveredBLEinfo = [[BLEinfoalloc] init];

//通过discoveredPeripheral这个属性保存了扫描到的peripheral,避免peripheral在当前方法结束后被释放

discoveredBLEinfo.discoveredPeripheral = peripheral;

discoveredBLEinfo.rssi = RSSI;

//更新 tableview数据源

[self saveBLE:discoveredBLEinfo];

}

BLEinfo是新建的工具类,用来保存扫描发现的蓝牙设备信息,具体如下:

#import <Foundation/Foundation.h>

#import <CoreBluetooth/CoreBluetooth.h>

@interface BLEinfo : NSObject

/**

*  扫描发现的蓝牙设备

*/

@property (nonatomic,strong)CBPeripheral *discoveredPeripheral;

/**

*  该蓝牙设备的信号质量,可以用来判断其距离中央设备的远近

*/

@property (nonatomic,strong)NSNumber *rssi;

@end

保存扫描中发现的蓝牙设备信息,并将它们展示到UITableView上:

- (BOOL)saveBLE:(BLEinfo *)discoveredBLEinfo{

for (BLEinfo * infoin self.arrayBLE) {

if ([info.discoveredPeripheral.identifier.UUIDStringisEqualToString:discoveredBLEinfo.discoveredPeripheral.identifier.UUIDString]) {

return NO;

}

}

[self.arrayBLEaddObject:discoveredBLEinfo];

[self.tableViewreloadData];

return YES;

}

扫描到的蓝牙设备展示如下:

2.连接设备

点击小米手环所在的cell,进入下一个页面BLEInfoViewController,在这个页面中开始连接小米手环。需要注意的是,要把上个页面中的centralManager传入到这个页面来用,并且重新设置delegate:

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

BLEinfo * info = [self.arrayBLEobjectAtIndex:indexPath.row];

BLEInfoViewController * BLEInfo = [[BLEInfoViewControlleralloc] init];

BLEInfo.centralManager =self.centralManager;

BLEInfo.discoveredPeripheral = info.discoveredPeripheral;

[self.navigationControllerpushViewController:BLEInfo animated:YES];

}

用来展示当前连接上的蓝牙设备的service和characteristic的UITableViewController:

#import <UIKit/UIKit.h>

#import <CoreBluetooth/CoreBluetooth.h>

@interface BLEInfoViewController :UITableViewController<CBPeripheralDelegate,CBPeripheralManagerDelegate,CBCentralManagerDelegate>

/**

*  用于管理中央设备的manager

*/

@property (nonatomic,strong)CBCentralManager *centralManager;

/**

* 被发现的周边设备

*/

@property (nonatomic,strong)CBPeripheral *discoveredPeripheral;

/**

*  tableview sections,保存蓝牙设备里面的services

*/

@property (nonatomic,strong)NSMutableArray *arrayServices;

/**

*  tableview rows,保存蓝牙设备里面每一个service中的每一个特性与对应的值

*/

@property (nonatomic,strong)NSMutableArray *arrayCharacteristics;

/**

* 用来记录有多少特性,当所有特性保存完毕,刷新表格

*/

@property (atomic,assign)int characteristicNum;

@end

把上个页面中的centralManager传入到这个页面来用,并且重新设置delegate:

- (void)viewDidLoad {

[superviewDidLoad];

[self.centralManagersetDelegate:self];

if (self.discoveredPeripheral) {

//开始连接蓝牙设备

[self.centralManagerconnectPeripheral:self.discoveredPeripheraloptions:nil];

}

self.arrayServices = [[NSMutableArrayalloc] init];

self.arrayCharacteristics = [[NSMutableArrayalloc] init];

self.characteristicNum =0;

}

成功连接到蓝牙设备时会来到下面这个方法:

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

//与周边设备连接成功时调用的代理方法

//清空原先的服务数组

[self.arrayServicesremoveAllObjects];

//清空原先的特征数组

[self.arrayCharacteristicsremoveAllObjects];

//设置蓝牙设备的代理

[self.discoveredPeripheralsetDelegate:self];

//开始发现当前蓝牙设备中的服务

[self.discoveredPeripheraldiscoverServices:nil];

}

3.获取服务

查找到服务之后会来到下面这个方法,在这个方法中把蓝牙设备中的服务保存到数组中

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

//成功搜索到蓝牙设备的服务时调用的方法

if (error) {

NSLog(@"didDiscoverServices  error : %@",error.localizedDescription);

return;

}

//将蓝牙设备中的服务保存到数组中

for (CBService * servicein peripheral.services) {

NSLog(@"Service found with UUID : %@",service.UUID);

NSMutableDictionary * dic = [[NSMutableDictionaryalloc] initWithDictionary:@{SECTION_NAME:service.UUID.description}];

[self.arrayServicesaddObject:dic];

//开始发现当前服务中的特性

[service.peripheraldiscoverCharacteristics:nilforService:service];

}

}

4.获取特性

-(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{

//成功搜索到蓝牙设备服务中的特性时调用的方法

if (error) {

NSLog(@"didDiscoverCharacteristicsForService error %@",error.localizedDescription);

return;

}

NSMutableArray * characteristics = [[NSMutableArrayalloc] init];

for (CBCharacteristic * cin service.characteristics) {

self.characteristicNum ++;

//读取每个特性对应的值

[peripheral readValueForCharacteristic:c];

[characteristics addObject:c];

}

[self.arrayCharacteristicsaddObject:characteristics];

}

5.读取特性值

在下面这个方法中可以通过characteristic.value获取到每个特性的值,类型是NSData。

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

//获取到特性值时调用的方法

if (error) {

NSLog(@"didUpdateValueForCharacteristic error %@",error.localizedDescription);

return;

}

self.characteristicNum --;

if (self.characteristicNum ==0) {

//所有服务中的特征值已读取完毕,更新表格

[self.tableViewreloadData];

}

}

6.重新连接

可能是小米手环中硬件设置的原因,蓝牙连接成功后30秒左右就会断开,需要在下面这个方法中重新进行蓝牙连接。

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

NSLog(@"%s",__FUNCTION__);

//与周边设备连接断开时调用的代理方法

//清空原先的服务数组

[self.arrayServicesremoveAllObjects];

//清空原先的特征数组

[self.arrayCharacteristicsremoveAllObjects];

//刷新表格,避免在连接断开时滑动表格出现的崩溃

[self.tableViewreloadData];

//重新与周边设备建立连接

[central connectPeripheral:peripheral options:nil];

}

7.写入数据

在获取到的小米手环的service中,最后一个service的UUID是0x1802,代表“Immediate Alert”。该service中有一个characteristic的UUID是0x2A06,代表“Alert level”。对这个characteristic写入不同的数值,可以使小米手环有不同的效果。点击这个characteristic所在的cell,进入下一个页面XiaoMiViewController,在这个页面中开始控制小米手环。需要注意的是,要把上个页面中的centralManager传入到这个页面来用,并且重新设置delegate:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

NSMutableArray * characteristics = [self.arrayCharacteristicsobjectAtIndex:indexPath.section];

CBCharacteristic * characteristic = [characteristicsobjectAtIndex:indexPath.row];

if ([characteristic.UUID.descriptionisEqualToString:@"2A06"]) {

XiaoMiViewController * XiaoMi = [[XiaoMiViewControlleralloc] init];

XiaoMi.centralManager =self.centralManager;

XiaoMi.discoveredPeripheral =self.discoveredPeripheral;

[self.navigationControllerpushViewController:XiaoMi animated:YES];

}

}

把上个页面一些必要的方法再实现一下。

- (void)viewDidLoad {

[superviewDidLoad];

self.title =@"小米手环";

[self.centralManagersetDelegate:self];

}

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

//重新与周边设备建立连接

[central connectPeripheral:peripheral options:nil];

}

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

//设置蓝牙设备的代理

[self.discoveredPeripheralsetDelegate:self];

//开始发现当前蓝牙设备中的服务

[self.discoveredPeripheraldiscoverServices:nil];

}

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

//开始发现当前蓝牙设备中每个服务里的每个特性

for (CBService * servicein peripheral.services) {

[service.peripheraldiscoverCharacteristics:nilforService:service];

}

}

接下来就是想要达到的效果啦。通过以下这个方法,对小米手环的指定service中的指定characteristic写入数值。

- (IBAction)weakShock {

for ( CBService *servicein self.discoveredPeripheral.services ) {

if ([service.UUID.descriptionisEqual:@"1802"]) {

for ( CBCharacteristic *characteristic in service.characteristics ) {

if ([characteristic.UUID.descriptionisEqual:@"2A06"]) {

/* EVERYTHING IS FOUND, WRITE characteristic ! */

//将int转成NSData

int i = 1;

NSData *data = [NSDatadataWithBytes: &i length: sizeof(i)];

[self.discoveredPeripheralwriteValue:data forCharacteristic:characteristictype:CBCharacteristicWriteWithoutResponse];

}

}

}

}

}

数值不同会有什么不一样的效果呢?传入1的话,小米手环会轻微震动;传入2的话,小米手环会强烈震动.....

蓝牙学习之①:调戏小米手环相关推荐

  1. 调戏小米手环2之认证原理

    小米手环2的连接认证机制 之所以小米手环2没有1那么方便调戏,是因为2中加入了认证机制,如果连接手环的中心设备不能完成认证,手环就会在十几秒后主动与中心设备断开连接,即使是在这几十秒里也只有对认证有关 ...

  2. 调戏小米手环2之发送文本通知

    在BLE标准中alert_notify服务的UUID为:00001811-0000-1000-8000-00805f9b34fb 其服务中文本通知的characteristic的UUID为:00002 ...

  3. 求解:如果通过蓝牙调试小米手环2?

    20200228 现状: 一只2016的小米手环2,JD入手,开始时一直带着,后来一年后屏幕越来越暗,放着吃灰. 疑问: 1.是什么原因导致小米手环2屏幕变暗,是老化还是程序设置(例如检测充电周期或电 ...

  4. 小米手环能不能用计算机,小米手环2怎么用,功能有哪些?小米手环2简易使用教程...

    作为国内最接地气的智能穿戴设备,搭载OLED屏幕的小米手环2拥有强大的续航和全面的功能,配合上出色的性价比,用作运动健身.健康监测甚至节日礼物都非常合适.但是对许多第一次接触智能穿戴的朋友来说,小米手 ...

  5. 小米手环/华为手环复制无法识别的加密校园卡(可刷门禁,只需一张卡,最简单方式)

    小米手环复制校园卡(最简单方式),解决小米手环不能复制门禁卡. 注意,这里的校园卡是加密卡,一般不容易破解,这里只是读取并写入0扇区的第一行数据,只能够身份识别充当门禁卡,不能进行消费等其他行为.(写 ...

  6. 小米手环8和小米手环7的区别

    1.主体尺寸区别 小米手环8主体尺寸为48*22.5*10.99mm: 小米手环7主体尺寸为46.5*20.7*12.25mm. 2.屏幕亮度区别 小米手环8屏幕亮度最高600nit,支持亮度自动调节 ...

  7. Android 小米手环蓝牙

    上一篇文章中我们已经认识了gatt的基本机构以及如何获得gatt中的Service以及Characteristic,接下来我们将学习对于Characteristic的基本操作,并使用这些基本操作,来操 ...

  8. iOS 蓝牙连接小米手环

    转自:http://blog.csdn.net/li_yangyang_li/article/details/51223615?locationNum=2&fps=1 1 前言 当前有越来越多 ...

  9. android 蓝牙低功耗(BLE)非常棒的工具类,获取小米手环的步数

    现在物联网搞的轰轰烈烈的,小米的手环等一系列产品,下面我们就来研究一下小米手环的记步功能 工具类 package com.zsl.bluetoothdemo.ble;import android.bl ...

最新文章

  1. 2010中国城市GDP排名
  2. 统计上报---日志上报成功率高的方式
  3. Angular self study 1 - Bootstrap
  4. Tomcat6.0 中数据源的配置
  5. 台积电南京12寸厂址 落脚江北新区
  6. Linux程序员必读:中文化与GB18030标准
  7. VB基础知识之Do...Loop循环
  8. c语言算法单循环球队比赛安排,单循环赛赛程安排算法研究.doc
  9. htmlunit第一个爬虫演示 目标网址http://ent.sina.com.cn/film/
  10. 我的世界java版幻翼_见到幻翼的方式是熬夜?这几个被忽略了
  11. 《计算机网络》在物理层和数据链路层扩展以太网
  12. django @csrf_exempt
  13. Unreal Engine 4 Radiant UI 入门教程(一)制作Radiant HUD
  14. python 12306登录_基于Python3的12306登录实现
  15. 武汉地铁站点最短路径搜索的实现(一)——Dijkstra算法(C++ coding)
  16. 基于Python企业公司网站设计与实现 开题报告
  17. 微信h5页面提交表单后返回键重复提交的问题
  18. 西北乱跑娃 -- fastapi设置静态文件以及跨域访问
  19. 数组索引越界异常 ArrayIndexOutOfBoundsException
  20. CF1019B:交互题+二分

热门文章

  1. 20221024-B站字幕的下载
  2. 1.5 20:球弹跳高度的计算
  3. word 中Visio画的图 如何修改?图片排列
  4. 算法导论-3.递归部分习题选
  5. JS中的函数参数传递到底是按值传递还是按引用传递
  6. 侍魂服务器维护,侍魂手游8月5日停机维护更新公告
  7. 千寻位置千寻知寸测试
  8. absolute定位宽高尺寸继承
  9. 二级渠道分销系统开发适合什么样的产品?
  10. cds云服务器_云探CDS拨测服务全面上线