【iOS官方文档翻译】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: 方法:
myCentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:nil];
在这个例子中,self会被设置为接收所有中心设备角色的事件的代理,设置dispatch queue为nil后,central manager会通过主线程来处理这些事件。ViewController需要实现CBCentralManagerDelegate,CBPeripheralDelegate这两个代理
当创建了一个central manager,会回调代理的centralManagerDidUpdateState:方法,你必须实现这个代理方法来确定中心设备是否支持BLE以及是否可用。
步骤二.搜索正在广告的外围设备
中心设备的第一个任务是搜索你的APP可以连接的外围设备,正如上一篇文章中提到的,广告(advertising)是外围设备使其被周围设备发现的主要方法,你可以通过CBCentralManager类的scanForPeripheralsWithServices:options: 方法,搜索任何正在广告的外围设备:
[myCentralManager scanForPeripheralsWithServices:nil options:nil];
你调用了scanForPeripheralsWithServices:options: 方法来搜索可连接的外围设备后,central manager 在每次搜索到一个外围设备都会回调其代理的centralManager:didDiscoverPeripheral:advertisementData:RSSI: 方法。任何被搜索到的外围设备都以CBPeripheral类的方式返回。像下面的代码,你可以实现这个代理方法来罗列出所有被搜索到的蓝牙设备:
- (void)centralManager:(CBCentralManager *)centraldidDiscoverPeripheral:(CBPeripheral *)peripheraladvertisementData:(NSDictionary *)advertisementDataRSSI:(NSNumber *)RSSI {NSLog(@"Discovered %@", peripheral.name);...
当你已经找到了一个你需要连接的外围设备,停止搜索其它设备来节省电量。
[myCentralManager stopScan];
NSLog(@"Scanning stopped”);
步骤三.连接一个你搜索到并希望连接的外围设备
在你搜索到一个外围设备,并且它广告了你需要的服务,你可以请求和这个外围设备连接,通过调用 CBCentralManager类的connectPeripheral:options:方法,简而言之,调用这个方法并且说明你需要连接的外围设备:
[myCentralManager connectPeripheral:peripheral options:nil];
假设连接成功了,central manager 会回调其代理方法centralManager:didConnectPeripheral: ,你可以实现这个方法来打印“外围设备连接”:
- (void)centralManager:(CBCentralManager *)centraldidConnectPeripheral:(CBPeripheral *)peripheral {NSLog(@"Peripheral connected");...
</pre><p></p><p style=""></p><p style="">在你开始和外围设备交互之前,你应该设置外围设备的代理以确保它能接收合适的回调,像这样</p><div><pre name="code" class="objc" style="color: rgb(102, 102, 102);">peripheral.delegate = self;
步骤四.搜索你已经连接的外围设备的服务
在你与外围设备建立连接之后,你可以开始勘察它的数据。第一步是勘察外围设备提供了什么服务,因为外围设备广告的数据有大小限制,你或许会发现外围设备提供比它广告的还有更多服务。你可以通过CBPeripheral类的discoverServices: 方法来发现一个外围设备提供的所有服务:
[peripheral discoverServices:nil];
当发现了具体的服务,外围设备(已经连接的 CBPeripheral类)会回调其代理的peripheral:didDiscoverServices: 方法。Core Bluetooth 建立CBService 类的array数组——存储外围设备的每一个服务。像下面的代码,你可以实现这个代理方法来获得发现的服务列表:
- (void)peripheral:(CBPeripheral *)peripheraldidDiscoverServices:(NSError *)error {for (CBService *service in peripheral.services) {NSLog(@"Discovered service %@", service);...}…
步骤五.搜索服务的特征
假定你已经找到了你需要的服务,下一步就是探索服务的所有“特征”(characteristics),搜索一个服务的所有特征只要调用 CBPeripheral类的discoverCharacteristics:forService:方法,参数为具体的服务:
NSLog(@"Discovering characteristics for service %@", interestingService);[peripheral discoverCharacteristics:nil forService:interestingService];
当发现了指定服务的特征,外围设备会回调peripheral:didDiscoverCharacteristicsForService:error:代理方法。Core Bluetooth建立存储CBCharacteristic实例的array数组———每一个都代表一个发现了的特征。下面的示例就是实现这个代理方法来简单地打印每个发现了的特征:
- (void)peripheral:(CBPeripheral *)peripheraldidDiscoverCharacteristicsForService:(CBService *)serviceerror:(NSError *)error {for (CBCharacteristic *characteristic in service.characteristics) {NSLog(@"Discovered characteristic %@", characteristic);...}...
步骤六.取得特征的值(就是从外围设备取数据)
一个特征包含一个代表外围设备服务的简单值,例如,有一个健康温度计服务,这个服务有一个温度测量特征,而这个特征有一个摄氏温度的值,你可以直接读取或者订阅这个特征来取得这个特征对应的值。
6.1直接读取特征的值
你得到你希望得到的服务的某个特征后,你可以通过调用CBPeripheral类的readValueForCharacteristic:方法来读取这个特征对应的值,参数为需要读取的特征:
NSLog(@"Reading value for characteristic %@", interestingCharacteristic);[peripheral readValueForCharacteristic:interestingCharacteristic];
当你试图去读一个特征对应的值,外围设备会回调它的代理方法
peripheral:didUpdateValueForCharacteristic:error:去取值,如果值成功返回,你可以通过特征的value属性来获得它:
- (void)peripheral:(CBPeripheral *)peripheraldidUpdateValueForCharacteristic:(CBCharacteristic *)characteristicerror:(NSError *)error {NSData *data = characteristic.value;// parse the data as needed...
6.2订阅一个特征的值
在某些使用情况下,通过 readValueForCharacteristic: 读取一个特征的值会很有效率,但是这不是获得值改变的最有效率方法,对于大部分特征值的改变——例如,你在给定时间的心率,你应该通过订阅来获得它。当你订阅了一个特征的值,你可以在值改变的时候接收到通知。你可以通过CBPeripheral类的setNotifyValue:forCharacteristic: 方法来订阅你需要的特征,参数为YES,以及需要订阅的特征:
[peripheral setNotifyValue:YES forCharacteristic:interestingCharacteristic];
当你试图去订阅(或取消订阅)一个特征时,外围设备会调用 它的代理的peripheral:didUpdateNotificationStateForCharacteristic:error:方法,如果订阅请求失败,你可以通过实现这个方法来获得错误原因:
- (void)peripheral:(CBPeripheral *)peripheraldidUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristicerror:(NSError *)error {if (error) {NSLog(@"Error changing notification state: %@",[error localizedDescription]);}...
当你成功订阅了某个特征,在特征的值改变时,外围设备会通知你的app,每次值改变,外围设备会调用 其代理的peripheral:didUpdateValueForCharacteristic:error:方法。你可以通过实现这个方法来获得改变的值,这个方法和上面直接读取时回调的方法一样。
步骤七.写值到特征中(就是发数据给外围设备)
在某些使用情况下,需要写数据到特征中,这是可行的。例如,你的app与一个BLE电子温度调节器交互,你或许需要提供给调节器一个值来设定房间的温度,如果特征的值可以被写,你可以通过CBPeripheral类的writeValue:forCharacteristic:type:方法把数据(NSData的实例)写到特征的值里:
NSLog(@"Writing value for characteristic %@", interestingCharacteristic);[peripheral writeValue:dataToWrite forCharacteristic:interestingCharacteristictype:CBCharacteristicWriteWithResponse];
当你试图去写特征的值时,你需要说明你需要用哪种类型的写的方法。上面的例子中,写的方法为CBCharacteristicWriteWithResponse,用这个方法,外围设备会让你的app知道写操作是否成功(就是)。更多写的方法请看CBPeripheral Class Reference里面的CBCharacteristicWriteType枚举。
使用CBCharacteristicWriteWithResponse方法给外围设备写数据时,会回调 其代理的peripheral:didWriteValueForCharacteristic:error:方法。如果写数据失败,可以通过这个方法找到失败的原因。像这样:
- (void)peripheral:(CBPeripheral *)peripheraldidWriteValueForCharacteristic:(CBCharacteristic *)characteristicerror:(NSError *)error {if (error) {NSLog(@"Error writing characteristic value: %@",[error localizedDescription]);}...
简单写了个测试demo,见下图,输入框为待发送的文本,Label为接收到的文本,我的蓝牙测试模块是返回我发送的数据。
这个demo只连接指定蓝牙名字的蓝牙设备,测试时,请将第十行的HMSoft改为自己的外围设备名称,这个demo比较水,每次viewdidload后就去搜索蓝牙设备并连接,不便于测试,自己可以加断点调试。
另外由于我的测试的蓝牙设备不支持CBCharacteristicWriteWithResponse,发送数据时都返回没有权限的错误,所以我用的CBCharacteristicWriteWithoutResponse。成功后不会回调didWriteValueForCharacteristic方法
下载demo :https://github.com/dolacmeng/Bluetooth
相关文章:

checkbox全选与反选
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>全选与反选</title><meta http-equiv"Content-Type" content"text/html;…
元组、列表及其特性
1、 #元组:带了紧箍咒的列表,不可直接修改元组内容 #元组本身不可变数据类型,没有增删改差 #元组内可以存储任意数据类型 t(1,2,3,4.2,star) print t,type(t) #元组内包含可变数组类型,可以间接修改元组内容 t1([1,2,3.3],4,5)…

JZOJ #4722 跳楼机 (最短路模型的完美转化)
题目描述: 给出$h,x,y,z$,求在$h$以内,$x,y,z$可以凑出多少个不同的数。$(1\leq{h}\leq{10^{18}},1\leq{x,y,z}\leq{10^5})$ 解题思路: 直接做显然不好做。我们考虑取$n$个$y$和$m$个$z$,然后再加上$x,2*x,3*x\cdots$&…
【C++】STL队列和栈的使用
C的STL标准模板库提供了队列和栈的基本操作。下面通过两个demo分别介绍STL队列和STL栈的使用。 Demo1:STL队列 【题目】卡片游戏(题目来自刘汝佳《算法竞赛入门》) 桌上又一叠牌,从第一张牌(即位于顶面的牌…

mongodb的shell命令
MongoDB常用命令: 超级用户相关: use admin #增加或修改用户密码 db.addUser(ixigua,pwd) #查看用户列表 db.system.users.find() #用户认证 db.auth(ixigua,pwd) #删除用户 db.removeUser(mongodb) #查看所有用户 show users #查看所有数据库 show dbs …
字典、集合及其特性
1、 字典的定义 """ 字典是一个无序的数据集合,使用print输出字典的时候 通常输出的顺序和定义的顺序是不一致的 """ message { name:tom, age:18, height:1.80, weight:75.5 } print message s {} prin…

[HDOJ2819]Swap(二分图最大匹配, 匈牙利算法)
题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid2819 题意:给一张n*n的01矩阵,可以任意交换其中的行或者列,问是否可以交换出来一个对角线上都是1的矩阵。 按行列号建图,如果(i,j)为1的话,则i和…

脚本路径问题_dirname
pwd可获取命令当前的路径 可是若我们想在脚本中获取脚本所在文件夹的路径,这种方法是不够用的。 例如,我们的脚本放在/home/user/script/下,名字叫做getpath.sh getpath.sh有一行脚本是了local_path$(pwd) 现在我们在/home/user/下࿰…
【iOS官方文档翻译】iOS蓝牙的基本概念
之前写了【iOS官方文档翻译】iOS的蓝牙连接、数据接收及发送一文,介绍了怎样进行蓝牙通讯,但是很多基本概念没有进行解释,看起来可能有点吃力,所以现在再翻译一篇苹果对官方蓝牙4.0一些基本概念介绍的文章。 1.中心设备和外围设备…
元组、列表、字典及集合练习
列表练习题: #假定有下面这样的列表: #names [lily, denny, jenny, apple] #输出结果为:I have lily,denny, jenny and apple. names [lily, denny, jenny, apple] print I have ,.join(names[:-1]) and names[-1] 2、后台管理前台会员信息 要求&#…
【iOS】sqlite3的使用(増删改查)
目录: 一、sqlite3常用函数 二、将sqlite3集成到项目,实现増删改查 三、封装DBManager 四、Demo 一、sqlite3常用函数及解释 (1)sqlite3_open: 用来创建和打开数据库文件,接收两个参数,第一个是数据库…

网上搜集了点资料,学web的人互相分享共同进步吧(php编码的好习惯必须养成)...
网上搜集了点资料,学web的人互相分享共同进步吧 一、优秀的代码应该是什么样的? 优秀的PHP代码应该是结构化的。大段的代码应该被分割整理成一个个函数或方法,而那些不起眼的小段代码则应该加上注释,以便日后清楚它们的用途。而且…

div模拟textarea文本域轻松实现高度自适应——张鑫旭
by zhangxinxu from http://www.zhangxinxu.com本文地址: http://www.zhangxinxu.com/wordpress/?p1362 一、关于textarea文本域以及高度自适应 textarea标签为表单元素,一般用在多行文字的输入。在web应用上常见的是评论输入框,微博信息输入…
【iOS】Mapkit的使用:地图显示、定位、大头针、气泡等
以前做项目用高德地图SDK,需要注册账号和AppID,然后下载SDK集成到项目中,比较麻烦,这几天看了下苹果自带的MapKit框架,感觉挺好用,官方文档也介绍得很详细,所以按照官方文档写了个demoÿ…
java.lang.NoSuchMethodError: org.springframework.core.io.ResourceEditor错误
一般是jar包冲突,或者某些jar包版本不同。 如上,spring其他包的版本均为4.2.5,而spring-webmvc的jar包为1.2.6版本,造成版本冲突。 把该包版本改为4.2.5,宣告成功! 转载于:https://www.cnblogs.com/toSeeMy…

SDUTOJ 1293 乘积最大的分解(数论)
乘积最大的分解思路: 让分解出来的因子有尽可能多的3,剩下的用2补全。 最开始思路错了,WA了好长时间 ! 函数中n 1的情况应该是不用,经测试数据中没有这组。 *注意用 long long 99的时候会超int的数据范围 1 #include …
列表及字典生成式
列表生成式: 列表生成式就是一个用来生成列表的特定语法形式的表达式。 语法格式: [exp for iter_var in iter] 迭代iter中的每个元素; 每次迭代都先把结果赋值给iter_var,然后通过exp得到一个新的计算值; 最后把…

[SQL基础教程] 1-5 表的删除和更新
[SQL基础教程] 1-5 表的删除和更新 表的删除 语法DROP TABLE <表名>; 法则 1-12 删除的表无法恢复 表定义的更新 语法ALTER TABLE<表名> ADD COLUMN<列的定义>; // 添加列 ALTER TABLE<表名> DROP COLUMN<列的定义>; // 删除列 ps: **Oracle、SQ…
【iOS】自定义控件入门:可拖动的环形进度
有时候UIKit的标准控件并不能满足我们的需求,因此我们可以通过自定义控件得到满足我们需求的控件,例如这篇文章将教你如何自定义一个圆形的进度条,并且用户可以通过拖动进度条上的手柄来改变进度值。主要参考了这篇文章:HOW TO BU…

在.NET2.0中解析Json和Xml
在.NET2.0中解析Json和Xml 在.NET解析json有很多方法,这里介绍最简单也用的最多的一种。 一、添加引用 解析Json,先下载开源控件 Newtonsoft.Json.dll 下载地址:http://files.cnblogs.com/gosky/Newtonsoft.Json%E9%9B%86%E5%90%88.zip 解压以…
虚拟机的基本操作
1、用户界面 [kioskfoundation156 Desktop]$ kiosk #打开shell的用户 #分隔符 foundation156 #主机名称 Desktop #工作目录名称 $ ##身份提示符,#表示超级用户,$表示普通用户 特别注意&a…

strong assign属性
strong:这要求运行时自动地保留对这个对象的引用。换而言之,ARC(Automatic Reference Counting)在运行时会一直把这个对象保留在内存里,直到它不再被任何其他对象引用。之后,其所占的内存会被自动释放。assign:表示这…

iOS7的界面上移问题
第一种方法:修改BaseSDK XCode5的默认BaseSDK是iOS7,所以要修改成工程文件创建时的BaseSDK。但是XCode5中默认只带有iOS7的SDK,所以要想能做到更改SDK,我们就要添加旧的SDK。 1.从苹果开发者中心下载旧版本XCode,https…
【Android】ActionBar的使用(1)
前(fei)言(hua):转行iOS开发半年,很久没接触Android了,前几天去上课,听着实在无聊,随手拿了同学的一本《Android UI设计》,发现有好多基础知识自己虽然用过&a…
装饰器及例题分析
知识点: 装饰器的定义: - 装饰器的实现是函数里面嵌套函数; - 装饰器的本质是一个函数, 它可以让其他函数在不需要做任何代码改动的前提下增加额外的功能; - 装饰器需要传递一个函数, 返回值也是一个函数对象. 1、map函数 def …

iOS开发系列--让你的应用“动”起来
概览 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌。在这里你可以看到iOS中如何使用图层精简非交互式绘图,如何通过核心动画创建基础动画、关键帧动画、动画组、转场动画,如何通…

ios app 砸壳
这里介绍使用dumpdecrypted砸壳。原理是用DYLD_INSERT_LIBRARIES这个环境变量加载脱壳的动态链接库dumpdecrypted.dylib 1.ssh连接上越狱的机器,输入密码alpine ssh root192.168.7.116 2.打开要砸的app,ps aux | grep var找到它的目录 yigewangde-iPhone…

基于visual Studio2013解决面试题之0804复杂链表
题目解决代码及点评/*复杂链表的拷贝,现在有一个复杂链表,完成一个clone函数拷贝一个链表复杂链表是指struct Node{struct Node* _next;struct Node* _sibling; // sibling指向链表中任意一个节点,或者…
python考试编程题
3. a: while True: s raw_input(变量名为:) if s exit: print 退出 break #判断是否由字母或下划线组成 if s[0].isalpha() or s[0] _: for i in s[1:]: if not (i.isalnum() or i _): print %s变量…

【分享】bootstrap学习笔记
一、基础知识 1.整体架构以响应式设计为理念,css组件、js插件jquery、基础布局组件和12栅格系统搭建。1.1响应式设计:结合media query查询,适应更多设备,自动适应用户的设备环境,不必为每个终端做一个特定的版本。2.cs…