小米手环iOS开发实战(一):iOS蓝牙框架CoreBluetooth

小米手环iOS开发实战(一):iOS蓝牙框架CoreBluetooth

本项目为对小米手环进行二次开发,利用了小米手环蓝牙连接并不安全的特性,连接后可以获取手环数据,并可修改数据。
本实例使用Swift3.0语言,Objective-C的蓝牙模块处理有略微不同,具体可见文档。
本节首先介绍iOS蓝牙框架CoreBluetooth,在此仅介绍本实例涉及到的蓝牙操作内容,如果大家有需要,可以专开一贴介绍CoreBluetooth的使用。


章节目录

  • iOS蓝牙框架介绍
  • CoreBluetooth.framework导入
  • CoreBluetooth的基础使用

iOS蓝牙框架介绍

CoreBluetooth介绍

在iOS开发中,实现蓝牙通信的方法有两种。分别是GameKit.framework以及CoreBluetooth.framework,前者在iOS5后基本被淘汰。

在苹果文档中,写了Communicate with Bluetooth 4.0 low-energy devices,也就是说仅支持蓝牙4.0低功耗协议(BLE)。

对于iOS10以上的设备,苹果注明以下信息:

An iOS app linked on or after iOS 10.0 must include in its Info.plist file the usage description keys for the types of data it needs to access or it will crash. To access Bluetooth peripheral data specifically, it must include NSBluetoothPeripheralUsageDescription.

也就是说需要声明并注册蓝牙权限的使用。

CoreBluetooth协议
首先提及蓝牙使用,在此引入两个概念:中心设备和外围设备。

  • 中心设备(客服端):作为中央管理器的设备,也就是本实例中的iOS设备。
  • 外围设备(服务器):也就是外部设备,扮演者产生数据的角色。许多传感器、蓝牙服务设备均是外围设备。本实例中小米手环就是外围设备。

同时数据传输还涉及到以下几个值:

  • UUID:相当与使用这个模块对映的应用的标识。
  • RSSI:信号强度,利用此信息可进行蓝牙测距,后面将进行讲解。

CoreBluetooth中涉及以下对象类:

  • CBCentralManager:中心设备类
  • CBPeripheral:外围设备类
  • CBCharacteristic:设备特征类

接下来就看一下如何导入蓝牙框架。


CoreBluetooth.framework导入

  1. 首先新建Xcode项目
  2. 在General->TARGETS->Linked Framworks and Libraries中点击添加并选择CoreBluetooth.framework导入。


    导入CoreBluetooth.framework
  3. 在代码中导入CoreBluetooth.framework
    Swift:import CoreBluetooth
    Objective-C:#import <CoreBluetooth/CoreBluetooth.h>
  4. 声明协议:使用CoreBluetooth需要支持CBCentralManagerDelegate, CBPeripheralDelegate协议,即前面所说的中心设备和外围设备,并实现相应方法


</br>

CoreBluetooth的基础使用

导入框架并声明协议后,即可开始实现必要方法。
下面通过展示整个流程所需要的方法

  • 初始化
var manager = CBCentralManager.init(delegate: self as? CBCentralManagerDelegate, queue: nil)
  • 扫描设备
switch manager.state {
        case .poweredOn:
            NSLog("正在扫描")
            manager.scanForPeripherals(withServices: nil, options: nil)
        default:
            break
        }

注:这里为什么一定要用switch语法?
因为CBCentralManager的State属性在之前是CBCentralManagerState,但是现在变成了CBManagerState,而需要iOS10以上才支持后者(23333)。这一波强制升级我是拒绝的,找了很多方法之后,发现这样写可以被Xcode接受而不去检查

  • 处理当前中心设备蓝牙状态
func centralManagerDidUpdateState(_ central: CBCentralManager) {
        switch central.state {
            case .poweredOn:
                NSLog("蓝牙已开启")
            default:
                NSLog("蓝牙未开启")
        }
    }
  • 扫描到外围设备的处理
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
    
        //peripheral.name为设备名称
        //可以调用CBCentralManager的stopScan停止扫描
        central.stopScan()
        //可以调用CBCentralManager的connect连接设备
        central.connect(peripheral, options: nil)
        }
    }
  • 成功连接到外围设备的处理
unc centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
        NSLog("成功连接")
        //设置代理
        peripheral.delegate = self
        //连接成功后接下来该扫描服务
        peripheral.discoverServices(nil)
    }
  • 连接失败的处理
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
        NSLog("连接设备失败")
    }
  • 扫描已连接外围设备服务
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
        if ((error) != nil) {
            NSLog("查找服务失败")
            return
        }
        else {
            for service in peripheral.services! {
                //扫描到服务后对服务逐个扫描特征值
                peripheral.discoverCharacteristics(nil, for: service)
           }
        }
    }
  • 扫描到特征值后的操作
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
        if ((error) != nil) {
            NSLog("扫描特征值失败")
        }
        else {
            for characteristic in service.characteristics! {
                //设置特征值只要有更新就获取
                peripheral.setNotifyValue(true, for: characteristic)
                
                if (characteristic.uuid.uuidString == "你想匹配的字符串") {
                    peripheral.readValue(for: characteristic)
                    //或
                    characSaver = characteristic
                }
            }
        }
    }

解释一下原理:方法对每个服务进行扫描,获取特征值。辨别是否是你想要的功能的特征值就要用到UUID,用UUID去匹配。匹配到后你可以选择保存他的特征值从而在后面自行操作,或者用readValue读取它的值,并由系统自动调用下面介绍的方法

  • 获取具体值之后的操作
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
        if ((error) != nil) {
            statusLabel.text = "从设备获取值失败"
            return
        }
        else {
            if(characteristic.uuid.uuidString == "特定值") {
                var infoBytes = [UInt8](characteristic.value!)
                var infoVal:Int = Int.init(infoBytes[0])
                NSLog("获取的值为:%d\n", infoVal)
            }
        }
    }

这里展示了一个示例操作,获取到手环的数据,由于手环的数据是最后8位Byte,所以取Byte值。但是由于Swift3.0已经取消了Byte,所以在此使用UInt8的类型转换来操作。对于你的蓝牙设备,根据数据的不同选择读取对应的位数。

这样,我们就完成了CoreBluetooth的方法,以及对应的处理。


对蓝牙框架CoreBluetooth的操作就告一段落,接下来将通过demo演示对控制小米手环进行讲解。如果对于蓝牙框架还有问题,欢迎提问或讨论。

GitHub:https://github.com/Minecodecraft
Demo链接:https://github.com/Minecodecraft/MiBandDemo

“小米手环iOS开发实战”系列
小米手环iOS开发实战(一):iOS蓝牙框架CoreBluetooth
小米手环iOS开发实战(二):开发Demo让你的手环振动起来

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 228,238评论 6 531
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 98,430评论 3 415
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 176,134评论 0 373
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 62,893评论 1 309
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 71,653评论 6 408
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 55,136评论 1 323
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 43,212评论 3 441
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 42,372评论 0 288
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 48,888评论 1 334
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 40,738评论 3 354
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 42,939评论 1 369
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 38,482评论 5 359
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,179评论 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 34,588评论 0 26
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 35,829评论 1 283
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 51,610评论 3 391
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 47,916评论 2 372

推荐阅读更多精彩内容