iOS的蓝牙连接 数据接收及发送
说明:苹果官方开发文档中涉及一些名词:Central(中心设备)、Peripheral(外围设备)、advertising(广告)、Services(服务)、Characteristic(特征)等,我都用括号内的中文进行翻译,并且不做详细解释,可能存在误导,请谅解。
目录:
步骤1.建立一个Central Manager实例进行蓝牙管理
步骤2.搜索外围设备
步骤3.连接外围设备
步骤4.获得外围设备的服务
步骤5.获得服务的特征
步奏6.从外围设备读数据(直接读取和订阅两种方法)
步骤7.给外围设备发送数据
步骤一.开启Central Manager
CBCentralManager 是Core Bluetooth的一个对象,代表一个本地中心设备,在使用任何蓝牙传输前,你必须给CBCentralManager实例分配内存和初始化。可以通过CBCentralManager类的initWithDelegate:queue:options: 方法:
1.
<p style=
"margin-top: 0px; margin-bottom: 0px; font-size: 18px; font-family: Courier; color: rgb(102, 102, 102); -webkit-text-stroke-color: rgb(102, 102, 102); -webkit-text-stroke-width: initial;"
>myCentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:nil];</p>
在这个例子中,self会被设置为接收所有中心设备角色的事件的代理,设置dispatch queue为nil后,central manager会通过主线程来处理这些事件。ViewController需要实现CBCentralManagerDelegate,CBPeripheralDelegate这两个代理
当创建了一个central manager,会回调代理的centralManagerDidUpdateState:方法,你必须实现这个代理方法来确定中心设备是否支持BLE以及是否可用。
步骤二.搜索正在广告的外围设备
中心设备的第一个任务是搜索你的APP可以连接的外围设备,正如上一篇文章中提到的,广告(advertising)是外围设备使其被周围设备发现的主要方法,你可以通过CBCentralManager类的scanForPeripheralsWithServices:options: 方法,搜索任何正在广告的外围设备:
1.
[myCentralManager scanForPeripheralsWithServices:nil options:nil];
你调用了scanForPeripheralsWithServices:options: 方法来搜索可连接的外围设备后,central manager 在每次搜索到一个外围设备都会回调其代理的centralManager:didDiscoverPeripheral:advertisementData:RSSI: 方法。任何被搜索到的外围设备都以CBPeripheral类的方式返回。像下面的代码,你可以实现这个代理方法来罗列出所有被搜索到的蓝牙设备:
01.
- (
void
)centralManager:(CBCentralManager *)central
02.
03.
didDiscoverPeripheral:(CBPeripheral *)peripheral
04.
05.
advertisementData:(NSDictionary *)advertisementData
06.
07.
RSSI:(NSNumber *)RSSI {
08.
09.
10.
11.
NSLog(@
"Discovered %@"
, peripheral.name);
12.
13.
...
当你已经找到了一个你需要连接的外围设备,停止搜索其它设备来节省电量。
1.
[myCentralManager stopScan];
2.
NSLog(@"Scanning stopped”);
步骤三.连接一个你搜索到并希望连接的外围设备
在你搜索到一个外围设备,并且它广告了你需要的服务,你可以请求和这个外围设备连接,通过调用 CBCentralManager类的connectPeripheral:options:方法,简而言之,调用这个方法并且说明你需要连接的外围设备:
1.
[myCentralManager connectPeripheral:peripheral options:nil];
假设连接成功了,central manager 会回调其代理方法centralManager:didConnectPeripheral: ,你可以实现这个方法来打印“外围设备连接”:
01.
- (
void
)centralManager:(CBCentralManager *)central
02.
03.
didConnectPeripheral:(CBPeripheral *)peripheral {
04.
05.
06.
07.
NSLog(@
"Peripheral connected"
);
08.
09.
...
1.
在你开始和外围设备交互之前,你应该设置外围设备的代理以确保它能接收合适的回调,像这样
1.
peripheral.delegate = self;
步骤四.搜索你已经连接的外围设备的服务
在你与外围设备建立连接之后,你可以开始勘察它的数据。第一步是勘察外围设备提供了什么服务,因为外围设备广告的数据有大小限制,你或许会发现外围设备提供比它广告的还有更多服务。你可以通过 CBPeripheral类的discoverServices: 方法来发现一个外围设备提供的所有服务:
1.
[peripheral discoverServices:nil];
当发现了具体的服务,外围设备(已经连接的 CBPeripheral类)会回调其代理的peripheral:didDiscoverServices: 方法。Core Bluetooth 建立CBService 类的array数组——存储外围设备的每一个服务。像下面的代码,你可以实现这个代理方法来获得发现的服务列表:
01.
- (
void
)peripheral:(CBPeripheral *)peripheral
02.
03.
didDiscoverServices:(NSError *)error {
04.
05.
06.
07.
for
(CBService *service in peripheral.services) {
08.
09.
NSLog(@
"Discovered service %@"
, service);
10.
11.
...
12.
13.
}
14.
15.
…
五.搜索服务的特征
假定你已经找到了你需要的服务,下一步就是探索服务的所有“特征”(characteristics),搜索一个服务的所有特征只要调用 CBPeripheral类的discoverCharacteristics:forService:方法,参数为具体的服务:
1.
NSLog(@
"Discovering characteristics for service %@"
, interestingService);
2.
3.
[peripheral discoverCharacteristics:nil forService:interestingService];
当发现了指定服务的特征,外围设备会回调peripheral:didDiscoverCharacteristicsForService:error:代理方法。Core Bluetooth建立存储CBCharacteristic实例的array数组———每一个都代表一个发现了的特征。下面的示例就是实现这个代理方法来简单地打印每个发现了的特征:
01.
- (
void
)peripheral:(CBPeripheral *)peripheral
02.
03.
didDiscoverCharacteristicsForService:(CBService *)service
04.
05.
error:(NSError *)error {
06.
07.
08.
09.
for
(CBCharacteristic *characteristic in service.characteristics) {
10.
11.
NSLog(@
"Discovered characteristic %@"
, characteristic);
12.
13.
...
14.
15.
}
16.
17.
...
六.取得特征的值(就是从外围设备取数据)
一个特征包含一个代表外围设备服务的简单值,例如,有一个健康温度计服务,这个服务有一个温度测量特征,而这个特征有一个摄氏温度的值,你可以直接读取或者订阅这个特征来取得这个特征对应的值。
直接读取特征的值
你得到你希望得到的服务的某个特征后,你可以通过调用CBPeripheral类的readValueForCharacteristic:方法来读取这个特征对应的值,参数为需要读取的特征:
1.
NSLog(@
"Reading value for characteristic %@"
, interestingCharacteristic);
2.
3.
[peripheral readValueForCharacteristic:interestingCharacteristic];
当你试图去读一个特征对应的值,外围设备会回调它的代理方法
peripheral:didUpdateValueForCharacteristic:error:去取值,如果值成功返回,你可以通过特征的value属性来获得它:
01.
- (
void
)peripheral:(CBPeripheral *)peripheral
02.
03.
didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic
04.
05.
error:(NSError *)error {
06.
07.
08.
09.
NSData *data = characteristic.value;
10.
11.
// parse the data as needed
12.
13.
...
订阅一个特征的值
在某些使用情况下,通过 readValueForCharacteristic: 读取一个特征的值会很有效率,但是这不是获得值改变的最有效率方法,对于大部分特征值的改变——例如,你在给定时间的心率,你应该通过订阅来获得它。当你订阅了一个特征的值,你可以在值改变的时候接收到通知。你可以通过 CBPeripheral类的setNotifyValue:forCharacteristic: 方法来订阅你需要的特征,参数为YES,以及需要订阅的特征:
1.
[peripheral setNotifyValue:YES forCharacteristic:interestingCharacteristic];
当你试图去订阅(或取消订阅)一个特征时,外围设备会调用 它的代理的peripheral:didUpdateNotificationStateForCharacteristic:error:方法,如果订阅请求失败,你可以通过实现这个方法来获得错误原因:
01.
- (
void
)peripheral:(CBPeripheral *)peripheral
02.
03.
didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic
04.
05.
error:(NSError *)error {
06.
07.
08.
09.
if
(error) {
10.
11.
NSLog(@
"Error changing notification state: %@"
,
12.
13.
[error localizedDescription]);
14.
15.
}
16.
17.
...
当你成功订阅了某个特征,在特征的值改变时,外围设备会通知你的app,每次值改变,外围设备会调用 其代理的peripheral:didUpdateValueForCharacteristic:error:方法。你可以通过实现这个方法来获得改变的值,这个方法和上面直接读取时回调的方法一样。
步骤七.写值到特征中(就是发数据给外围设备)
在某些使用情况下,需要写数据到特征中,这是可行的。例如,你的app与一个BLE电子温度调节器交互,你或许需要提供给调节器一个值来设定房间的温度,如果特征的值可以被写,你可以通过 CBPeripheral类的writeValue:forCharacteristic:type:方法把数据(NSData的实例)写到特征的值里:
1.
NSLog(@
"Writing value for characteristic %@"
, interestingCharacteristic);
2.
3.
[peripheral writeValue:dataToWrite forCharacteristic:interestingCharacteristic
4.
5.
type:CBCharacteristicWriteWithResponse];
当你试图去写特征的值时,你需要说明你需要用哪种类型的写的方法。上面的例子中,写的方法为CBCharacteristicWriteWithResponse,用这个方法,外围设备会让你的app知道写操作是否成功(就是)。更多写的方法请看 CBPeripheral Class Reference里面的CBCharacteristicWriteType枚举。
使用CBCharacteristicWriteWithResponse方法给外围设备写数据时,会回调 其代理的peripheral:didWriteValueForCharacteristic:error:方法。如果写数据失败,可以通过这个方法找到失败的原因。像这样:
01.
- (
void
)peripheral:(CBPeripheral *)peripheral
02.
03.
didWriteValueForCharacteristic:(CBCharacteristic *)characteristic
04.
05.
error:(NSError *)error {
06.
07.
08.
09.
if
(error) {
10.
11.
NSLog(@
"Error writing characteristic value: %@"
,
12.
13.
[error localizedDescription]);
14.
15.
}
16.
17.
...
简单写了个测试demo,见下图,输入框为待发送的文本,Label为接收到的文本,我的蓝牙测试模块是返回我发送的数据。
这个demo只连接指定蓝牙名字的蓝牙设备,测试时,请将第十行的HMSoft改为自己的外围设备名称,这个demo比较水,每次viewdidload后就去搜索蓝牙设备并连接,不便于测试,自己可以加断点调试。
另外由于我的测试的蓝牙设备不支持CBCharacteristicWriteWithResponse,发送数据时都返回没有权限的错误,所以我用的CBCharacteristicWriteWithoutResponse。成功后不会回调didWriteValueForCharacteristic方法
下载demo :https://github.com/dolacmeng/Bluetooth
iOS的蓝牙连接 数据接收及发送相关推荐
- 一分钟读懂低功耗蓝牙连接数据包
一分钟读懂低功耗蓝牙(BLE)连接数据包 1.概述 BLE 连接过程中有三个重要的数据包:SCAN_REQ, SCAN_RSP 和 CONNECT_REQ. SCAN_REQ: 扫描请求, ...
- Udp数据接收和发送代码
每一台电脑都有自己的ip地址,向指定的ip地址发数据,数据就发送到了指定的电脑.UDP通信只是一种通信方式而已,有了ip地址数据就能发送到指定的电脑了,但是呢!我把数据发送到电脑了,电脑中的哪个程序接 ...
- C#对串口数据接收、发送的处理
最近在做与设备进行串口通信交互的项目,然后简单记录一下过程 使用的winform应用程序 方式1 1.声明串口对象 或者直接在工具箱拖拽串口控件 本篇文章不采用拖拽工具箱控件 直接声明对象 声明串口对 ...
- 【iOS官方文档翻译】iOS的蓝牙连接、数据接收及发送
说明:苹果官方开发文档中涉及一些名词:Central(中心设备).Peripheral(外围设备).advertising(广告).Services(服务).Characteristic(特征)等,请 ...
- ESP32-C3入门教程 问题篇⑬——IOS手机蓝牙连接容易断开问题,BT_HCI: DiscCmpl evt: hdl=1, rsn=0x8
文章目录 一.前言 二.发现问题 三.解决问题 一.前言 本文基于VS Code IDE进行编程.编译.下载.运行等操作 基础入门章节请查阅:ESP32-C3入门教程 基础篇①--基于VS Code构 ...
- linux C - TCP数据接收和发送示例
[推荐阅读] 浅谈linux 内核网络 sk_buff 之克隆与复制 深入linux内核架构--进程&线程 了解Docker 依赖的linux内核技术 1.client端(读) #includ ...
- C#,COM口,接收,发送数据
这里写一种,COM口的数据接收,发送方法. 1.COMHelper类 1 /// <summary>初始化串行端口</summary> 2 private SerialPort ...
- 【Flink实战系列】为什么我的Flink任务正常运行,UI上却不显示接收和发送的数据条数呢?
最近发现有好几个同学问我这个问题,为什么我的Flink任务正常运行,数据也可以打印,而且都保存到数据库了,但是UI上面却不显示数据接收和发送的条数,我都快被问疯了,今天就给大家详细说一下这个小问题. ...
- 熊晨沣蓝牙实战--小程序蓝牙连接2.0
微信小程序蓝牙连接2.0说明: 1.本版本区分了ANDROID和IOS系统下蓝牙连接的不同方式. 2.兼容了更多情况下的链接包括: (1)未开启设备蓝牙,当监听到开启了蓝牙后自动开始连接. (2)初始 ...
最新文章
- mysql-事物实现原理
- 小程序直播间页面路径怎么访问直播间_以小程序为例,在线教育产品的直播间有哪些功能设计?...
- 二次优化问题dfp_优化设计-fmincon函数介绍-序列二次的规划(SQP)-subspacetrustregion-activesett.pdf...
- oracle+sid+未清除,管理信息化ORACLEoracle+DBA手册.pdf
- php 发那科,FANUC发那科CNC数据采集教程连接CNC
- (错误记录)git push 报错 403
- [Regular] 2、正则表达式基础元字符及分组、捕获
- python虚拟环境和pyenv_Python多版本管理器pyenv和虚拟环境pyenv-virtualenv的安装设置...
- python中search和match的区别_Python中正则表达式match()、search()函数及match()和search()的区别详解...
- 90亿拿下德邦 京东物流加速“造血”
- 【XAMPP启动mysql报错】Port 3306 in use by ““C:\Program Files\MySQL\MySQL Server 5.5\bin\mysqld“……
- yum install php-pecl-mongo,pecl安装php mongodb扩展
- Xcode中打印显示Unicode的解决办法
- Halcon标定系列(3):我个人总结的“眼在手外“和“眼在手上”的心得笔记
- protel 99se 层次原理图的切换
- Android——实现光点模糊渐变的自旋转圆环特效
- 吉他音阶训练入门教程——问题解答(一)
- [计算机基础]浮点数在计算机中的表示
- 互动媒体技术A1作业报告
- 更快地编写更好的代码:5 分钟阅读