看过一些蓝牙App的事例,大体上对蓝牙的连接过程进行了了解。但是开始真正自己写一个小的BLE程序的时候就举步维艰了。那些模棱两可的概念在头脑中瞬间就蒸发了,所以还是决定从最基本的蓝牙连接过程进行。这里所说的蓝牙是针对 bluetooth 4.0的。

  第一步就是去看官方的关于蓝牙框架的文档,即Core Bluetooth Programming Guide在苹果的官方网站上可以轻松找到,不管你对蓝牙的基本概念是否有了解,这个文件可以使你更好的对蓝牙的连接过程有个了解。这个文档的前面几张介绍了关于bluetooth 4.0开发过程中必要的概念(这些概念必不可少,一定要搞懂,否则后面会搞得很乱),真正开始将连接过程是从Performing Common Central Role Tasks 这一章开始,这里很清晰的将过程分成了以下这么几步,每一步对有对应的接口函数,只需要按着这一步一步写下去就可以。

  • Start up a central manager object
  • Discover and connect to peripheral devices that are advertising
  • Explore the data on a peripheral device after you’ve connected to it
  • Send read and write requests to a characteristic value of a peripheral’s service
  • Subscribe to a characteristic’s value to be notified when it is updated

  针对每一步我将我的Swift所对应的代码列出来:

Starting Up a Central Manager

将CBCenteralManager实例化,如下:

     //start up a central manager object
func startCentralManager(){
myCentralManager = CBCentralManager(delegate: self, queue: nil)
}

当实例化成功后,对调用如下函数:

     func centralManagerDidUpdateState(central: CBCentralManager!){
println("CentralManager is initialized") switch central.state{
case CBCentralManagerState.Unauthorized:
println("The app is not authorized to use Bluetooth low energy.")
case CBCentralManagerState.PoweredOff:
println("Bluetooth is currently powered off.")
case CBCentralManagerState.PoweredOn:
println("Bluetooth is currently powered on and available to use.")
default:break
}
}

此时CBCenteralManager实例化完毕,就可以开始进行扫描外设了。

2、Discovering Peripheral Devices That Are Advertising

OC中扫描函数是:

 [myCentralManager scanForPeripheralsWithServices:nil options:nil];

在swift中对应的是:

 myCentralManager!.scanForPeripheralsWithServices(nil , options: nil)

当发现设备后,会调用如下的函数,这样我们就可以对设备进行一定的操作,当发现设备后接下来应该是连接设备。

     func centralManager(central: CBCentralManager!, didDiscoverPeripheral peripheral: CBPeripheral!, advertisementData: [NSObject : AnyObject]!, RSSI: NSNumber!) {
println("CenCentalManagerDelegate didDiscoverPeripheral")
println("Discovered \(peripheral.name)")
println("Rssi: \(RSSI)") println("Stop scan the Ble Devices")
myCentralManager!.stopScan()
cbPeripheral = peripheral }

3、Connecting to a Peripheral Device After You’ve Discovered It

OC中连接设备的代码是:

 [myCentralManager connectPeripheral:peripheral options:nil];

Swift中的代码是:

 myCentralManager!.connectPeripheral(cbPeripheral!, options: nil)

连接的结果会调用下面三个回调函数

     func centralManager(central: CBCentralManager!, didConnectPeripheral peripheral: CBPeripheral!) {
println("CenCentalManagerDelegate didConnectPeripheral")
println("Connected with \(peripheral.name)")
peripheral.delegate = self peripheral.discoverServices(nil)
} func centralManager(central: CBCentralManager!, didFailToConnectPeripheral peripheral: CBPeripheral!, error: NSError!) {
println("CenCentalManagerDelegate didFailToConnectPeripheral")
} func centralManager(central: CBCentralManager!, didDisconnectPeripheral peripheral: CBPeripheral!, error: NSError!) {
println("CenCentalManagerDelegate didDisconnectPeripheral")
}

具体含义可以查询官方文档。

注意:连接设备的函数不能在didDiscoverPeripheral回调函数中直接调用,这样是无法连接的,这个问题也困扰了我一会,后面歪打正着就成了, 要么设一个延迟再去connect,要么加个按钮触发事件再去连接。

4、Discovering the Services of a Peripheral That You’re Connected To

当连接完毕后,就是扫描这个外设(Peripheral)所支持服务。然后可以保存下来,下次可以直接调用

OC中扫描Services的代码如下:

 [peripheral discoverServices:nil];

Swift中如下:

 peripheral.discoverServices(nil)

当扫描到Service后对调用下面的回调函数:

 func peripheral(peripheral: CBPeripheral!, didDiscoverServices error: NSError!) {
println("CBPeripheralDelegate didDiscoverServices")
for service in peripheral.services {
println("Discover service \(service)")
println("UUID \(service.UUID)")
if(service.UUID == CBUUID.UUIDWithString("")){
println("Immediate_Alert_Service")
immediateAlertService = (service as CBService)
peripheral.discoverCharacteristics(nil , forService: immediateAlertService)
}else if(service.UUID == CBUUID.UUIDWithString("")){
println("Link_Loss_Service")
linkLossAlertService = (service as CBService)
peripheral.discoverCharacteristics(nil , forService: linkLossAlertService)
}
}
}

扫描到Service后,要遍历这个Service所包含的Characteristics。

5、Discovering the Characteristics of a Service

扫描Characteristics

  peripheral.discoverCharacteristics(nil , forService: linkLossAlertService)

和扫描Services一样,会有回调函数

 func peripheral(peripheral: CBPeripheral!, didDiscoverCharacteristicsForService service: CBService!, error: NSError!) {
for characteristic in service.characteristics{ if(service == immediateAlertService && characteristic.UUID == CBUUID.UUIDWithString("2A06")){
println("immediateAlertService Discover characteristic \(characteristic)")
alertLevelCharacteristic = (characteristic as CBCharacteristic)
//immediateAlertCharacter 写入是有问题的
// cbPeripheral!.writeValue(NSData(bytes: &alertLevel, length: 1), forCharacteristic: characteristic as CBCharacteristic, type: CBCharacteristicWriteType.WithResponse)
}else if(service == linkLossAlertService && characteristic.UUID == CBUUID.UUIDWithString("2A06")){
println("linkLossAlertService Discover characteristic \(characteristic)")
linkLossAlertCharacteristic = (characteristic as CBCharacteristic)
//linkLossAlertCharacteristic 写入没有问题,所以通过这个写入来进行绑定
cbPeripheral!.writeValue(NSData(bytes: &alertLevel, length: ), forCharacteristic: characteristic as CBCharacteristic, type: CBCharacteristicWriteType.WithResponse)
}
}
}

这样就把每个Service所对应的Characteristics给读取出来了。

6、Retrieving the Value of a Characteristic

  • Reading the Value of a Characteristic
 cbPeripheral!.readValueForCharacteristic(alertLevelCharacteristic!)

值在回调函数中获取,在read之前,要注意这个Characteristic是否可读。

     func peripheral(peripheral: CBPeripheral!, didUpdateValueForCharacteristic characteristic: CBCharacteristic!, error: NSError!) {
if(error != nil){
println("Error Reading characteristic value: \(error.localizedDescription)")
}else{
var data = characteristic.value
println("Update value is \(data)")
} }
  • Writing the Value of a Characteristic
 var alertLevel:Byte = 0x02
cbPeripheral!.writeValue(NSData(bytes: &alertLevel, length: ), forCharacteristic: alertLevelCharacteristic!, type: CBCharacteristicWriteType.WithoutResponse)

写是否成功会根据CBCharacteristicWriteType来决定是否调用下面的回调函数:

 func peripheral(peripheral: CBPeripheral!, didWriteValueForCharacteristic characteristic: CBCharacteristic!, error: NSError!) {
if(error != nil){
println("Error writing characteristic value: \(error.localizedDescription)")
}else{
println("Write value success!")
} }

关于write我这里还有些注意的地方要强调!!!!

并不是每一个Characteristic都可以通过回调函数来查看它写入状态的。就比如针对 immediateAlertService(1802) 的 alertLevelCharacteristic(2A06),就是一个不能有response的Characteristic。刚开始我就一直用CBCharacteristicWriteType.WithResponse来进行写入始终不成功,郁闷坏了,最后看到每个Characteristic还有个属性值是指示这个的,我将每个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
SWIFT
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.

就是当发生读写交互时,系统在会和外设进行绑定操作!!!

基于swift语言iOS8的蓝牙连接(初步)的更多相关文章

  1. Swift语言iOS8的蓝牙Bluetooth解析

    开发中央步骤: 1.添加CoreBluetooth.framework框架到你的工程 2.继承两个协议:CBCentralManagerDelegate和CBPeripheralDelegate 个人 ...

  2. Swift语言—有趣的字符串连接、数组、字典

    字符串链接:Swift语言中的字符串连接方式本人觉得非常的有趣,变量连接需要用右斜杠,并且变量名要括起来 “\(变量名)”,后面的字符串连接分别用逗号 ‘ , ’ 隔开 数组: Var arr = [ ...

  3. 基于Swift语言开发微信、QQ和微博的SSO授权登录代码分析

    前言 Swift 语言,怎么说呢,有一种先接受后排斥.又欢迎的感觉,纵观国外大牛开源框架或项目演示,Swift差点儿占领了多半,而国内尽管出现非常多相关技术介绍和教程,可是在真正项目开发中使用的占领非 ...

  4. IOS蓝牙连接 初步简单封装使用

    最近写一个蓝牙项目 初步实现一下蓝牙设备连接交互,后期继续完善.... 1.连接蓝牙相关操作 BlueToothManger.h // // BlueToothManger.h // SmartRob ...

  5. Swift语言快速入门

    Swift语言快速入门(首部同步新版官方API文档和语法的Swift图书,确保代码可编译,作者专家在线答疑,图书勘误实时跟进) 极客学院 编著   ISBN 978-7-121-24328-8 201 ...

  6. Swift语言高速入门

    Swift语言高速入门(首部同步新版官方API文档和语法的Swift图书,确保代码可编译,作者专家在线答疑,图书勘误实时跟进) 极客学院 编著   ISBN 978-7-121-24328-8 201 ...

  7. 初步swift语言学习笔记9(OC与Swift杂)

    笔者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/34440159 转载请注明出处 假设认为文章对你有所帮助,请通过留言 ...

  8. Swift语言iOS开发:CALayer十则示例

    如你所知,我们在iOS应用中看到的都是视图(view),包括按钮视图.表视图.滑动条视图,还有可以容纳其他视图的父视图等. AD:[活动]Web和APP兼容性实战 Win10训练营免费报名 如你所知, ...

  9. 如何用 Swift 语言构建一个自定控件

    (via:破船之家,原文:How To Make a Custom Control in Swift)   用户界面控件是所有应用程序重要的组成部分之一.它们以图形组件的方式呈现给用户,用户可以通过它 ...

随机推荐

  1. 《App研发录》知识点汇总

    原文链接:http://www.jianshu.com/p/fc8c4638937e <App研发录>这部书是包建强写的,说来也巧,在读这边书之前在看池建强的<Mac 人生元编程&g ...

  2. python的文件操作方法

    python中的文件对象:文件对象不仅可以用来访问普通的磁盘文件, 而且也可以访问任何其它类型抽象层面上的"文件". 一旦设置了合适的"钩子", 你就可以访问具 ...

  3. spring注解 构造函数问题

    因为类首先被Spring实例化的时候,会调用构造函数.只有实例化后,才会注入.你等于没注入就调用了,所以报错. 把DAO实现类注入到service实现类中,把service的接口(注意不要是servi ...

  4. VBS创建数据表

    '创建数据表'参数:strDBPath 字符串型 数据库路径'参数:strTableName 字符串型 需要创建的数据表的名称'参数:strColumnName 字符串型 初始化的字段名称,其实可以算 ...

  5. dedecms后台登录如何去除验证码设置

    dedecms后台验证有时间输入总是不对,有时候却不显示,而输入验证码无疑是一个麻烦的过程,那么我们怎么样来去除后台验证码,实现输入帐号密码直接登录呢?我来为大家介绍一下: 让人感到烦恼的情况出现了! ...

  6. nodejs安装及环境配置

    简单的说 Node.js 就是运行在服务端的 JavaScript. Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台. Node.js是一个事件驱动I/O服务端Ja ...

  7. 九度OJ 1544 数字序列区间最小值

    题目地址:http://ac.jobdu.com/problem.php?pid=1544 题目描述: 给定一个数字序列,查询任意给定区间内数字的最小值. 输入: 输入包含多组测试用例,每组测试用例的 ...

  8. 取得Android平台某设备上所有可用的Sensors

    本来要写一个检测手机的温度的小应用,学习一下传感器的api,可结果怎么写不行.经检测,发现取得的Sensor为NULL,这才明白,我手机没有TYPE_AMBIENT_TEMPERATURE传感器. 于 ...

  9. 搭建高性能计算环境(四)、应用软件的安装之VASP

    1,将需要的软件包上传vasp.5.2.12.tar.gz.vasp.5.lib.tar.gz.benchmark.Hg.tar.gz. 2,创建vasp目录并解压软件包. mkdir /opt/va ...

  10. Objective-C数据类型、数据类型转换

    数据类型 1.Objective-C数据类型可以分为:基本数据类型.对象数据类型和id类型. 2.基本数据类型有:int.float.double和char类型. 3.对象类型就是类或协议所声明的指针 ...