低功耗蓝牙原理与实现

最近公司提出一个需求:如果当前安卓手机支持BLE(Bluetooth Low Energy 低功耗蓝牙),则需要将当前的手机和车机通过蓝牙进行互联,并实现通信。由于之前没有接触过BLE相关的内容,实现的过程中遇到了许多困难,但也因此学到了不少的知识,因此想写下这篇文章与大家分享。文章主要包括以下几个内容:

  1. BLE原理详解
  2. BLE相关的几个概念详解
  3. BLE相关的几个类详解
  4. BLE实现的前提条件
  5. BLE使用的一般流程
  6. BLE使用过程中遇到的一些坑
  7. 参考资料

原理详解

  1. 蓝牙通信的主从关系

蓝牙技术规定每一对设备之间进行蓝牙通讯时,必须一个为主角色,另一为从角色,才能进行通信,通信时,必须由主端进行查找,发起配对,建链成功后,双方即可收发数据。理论上,一个蓝牙主端设备,可同时与7个蓝牙从端设备进行通讯。一个具备蓝牙通讯功能的设备,可以在两个角色间切换,平时工作在从模式,等待其它主设备来连接,需要时,转换为主模式,向其它设备发起呼叫。一个蓝牙设备以主模式发起呼叫时,需要知道对方的蓝牙地址,配对密码等信息,配对完成后,可直接发起呼叫。这可以解释为什么有时无法连接蓝牙,有可能是连接的蓝牙设备过多。

  1. 蓝牙的呼叫过程

蓝牙主端设备发起呼叫,首先是查找,找出周围处于可被查找的蓝牙设备。主端设备找到从端蓝牙设备后,与从端蓝牙设备进行配对,此时需要输入从端设备的PIN码,也有设备不需要输入PIN码。配对完成后,从端蓝牙设备会记录主端设备的信任信息,此时主端即可向从端设备发起呼叫,已配对的设备在下次呼叫时,不再需要重新配对。已配对的设备,做为从端的蓝牙耳机也可以发起建链请求,但做数据通讯的蓝牙模块一般不发起呼叫。链路建立成功后,主从两端之间即可进行双向的数据或语音通讯。在通信状态下,主端和从端设备都可以发起断链,断开蓝牙链路。

  1. 蓝牙一对一的串口数据传输应用

蓝牙数据传输应用中,一对一串口数据通讯是最常见的应用之一,蓝牙设备在出厂前即提前设好两个蓝牙设备之间的配对信息,主端预存有从端设备的PIN码、地址等,两端设备加电即自动建链,透明串口传输,无需外围电路干预。一对一应用中从端设备可以设为两种类型,一是静默状态,即只能与指定的主端通信,不被别的蓝牙设备查找;二是开发状态,既可被指定主端查找,也可以被别的蓝牙设备查找建链。


低功耗蓝牙相关的几个概念详解

  1. BLE 全称为Bluetooth Low Energy,即低功耗蓝牙
  2. GATT 全称为Generic Attribute Profile,即通用属性协议
    通过BLE连接,读写属性类小数据的Profile通用规范。现在所有的BLE应用Profile都是基于GATT的。GATT包含若干个Profile,一个Profile包含若干个Services,一个Service包含若干个Characteristics,一个Characteristic包含Properties字段和若干个Descriptor(可选)。
    GATT调用下层的ATT,ATT的attirbute在GATT中表现为Characteristic。有关GATT相关的东西,这篇博客写的很清楚,有兴趣的朋友可以看看。Generic Attribute Profile (GATT) 通用属性协议
  3. ATT 全称Attribute Protocol
    GATT是基于ATT Protocol的。ATT针对BLE设备做了专门的优化,具体就是在传输过程中使用尽量少的数据。每个属性都有一个唯一的UUID,属性将以characteristics and services的形式传输。
  4. UUID 全称Universally Unique Identifier,即通用唯一识别码
    在BLE中,所有的Service,Service包含的Characteristic,以及Characteristic包含的Descriptor都是通过UUID进行标识的。
  5. Service
    Characteristic的集合。例如一个service叫做“Heart Rate Monitor”,它可能包含多个Characteristics,其中可能包含一个叫做“heart ratemeasurement”的Characteristic。一个手环可能。
  6. Characteristic
    Characteristic可以理解为一个数据类型,它包括一个value和0至多个对次value的描述(Descriptor)。
  7. Descriptor
    对Characteristic的描述,例如范围、计量单位等。

低功耗蓝牙相关的几个类详解

  1. BluetoothManager。通过Context.getSystemService(Context.BLUETOOTH_SERVICE)获得,主要是用于获取BluetoothAdapter实例。
  2. BluetoothAdapter。BLE的主要操作都是通过BluetoothAdapter来实现的,比如判断当前设备的BLE是否可用,是否打开,以及扫描,停止扫描,获取远程设备等。
  3. BluetoothDevice。代表设备上发现的BLE设备,相当于一个Bean,里面包含BLE设备的许多信息,比如蓝牙的名称,蓝牙的地址,同时也是通过它进行连接操作的,同时返回一个BluetoothGatt对象等等。
  4. BluetoothGatt。包含一些 Bluetooth GATT Profile公用的API,比如发现服务,读数据,写数据,判断设备是否在连接状态,断开连接等等。
  5. BluetoothGattService。代表一个Bluetooth GATT Service
  6. BluetoothGattCharacteristic。Represents a Bluetooth GATT Characteristic
  7. BluetoothGattDescriptor。代表一个Bluetooth GATT Descriptor

实现的前提条件

首先当前的设备必须要支持BLE,且Android系统必须在4.3或以上。和经典蓝牙一样,应用使用蓝牙,需要声明BLUETOOTH权限,如果需要扫描设备或者操作蓝牙设置,则还需要BLUETOOTH_ADMIN权限:

除了蓝牙权限外,如果需要BLE feature则还需要声明uses-feature:按时required为true时,则应用只能在支持BLE的Android设备上安装运行;required为false时,Android设备均可正常安装运行,需要在代码运行时判断设备是否支持BLE feature:

if(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)){
    Toast.makeText(this, R.string.ble_not_supported,Toast.LENGTH_SHORT).show();
    finish();
}

低功耗蓝牙使用的一般流程

  1. 在AndroidManifest文件中添加相关的权限和相关的特征;
  2. 检查当前设备是否支持BLE,并且蓝牙是否打开;
  3. 扫描设备;
  4. 连接指定设备;
  5. 对指定设备进行读写等操作;
  6. 断开连接;
  7. 关闭蓝牙

使用过程中遇到的一些坑

  1. 扫描到蓝牙后,除了BluetoothDevice里面发现的名称和地址之外,没有获取设备里包含的更多信息:在BluetoothAdapter.LeScanCallback中的onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord)回调函数,第三个参数scanRecord中包含了更多远程设备的信息。
  2. 写数据收不到反馈信息(onCharacteristicChanged()函数就是不回调):首先要确保打开了对应的通知,其次要确保相应的Descriptor执行了类似以下的操作:
if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
    BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
        UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
    descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
    mBluetoothGatt.writeDescriptor(descriptor);
}
  1. 写数据写两次才能收到反馈信息:这个问题真的是非常奇怪,就是明明用正确的方式打开了通知,可是就是收不到数据,但是写两次就可以收到数据。后来的解决方案是:在打开通知以后,延迟1秒进行写操作,就成功了。想必应该是打开通知也是需要时间的,必须在通知打开完成之后,进行写操作才能收到对象的信息。
  2. 发现服务后,在ExpandableListView中无法显示数据:解决方案也是通过Handler延迟0.5S左右就可以正常显示了。

参考资料

  1. BLE简介和Android BLE编程
  2. Generic Attribute Profile (GATT) 通用属性协议
  3. android ble 的各种坑
  4. Android 蓝牙4.0 ble 官方 demo
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,002评论 6 509
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,777评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,341评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,085评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,110评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,868评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,528评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,422评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,938评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,067评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,199评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,877评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,540评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,079评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,192评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,514评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,190评论 2 357

推荐阅读更多精彩内容