Android之低功耗蓝牙的基本使用

作者: 木木00 | 来源:发表于2017-05-05 14:25 被阅读316次

    作者简介  创微信公众号郭霖 WeChat ID: guolin_blog

    早上好,五一放假回来的第二天,相信大家已经回到工作状态了吧,那么我们今天继续分享干货。

    本篇来自Xanthuim的投稿,介绍了蓝牙常见的使用方式,并分享了自己的项目,希望对大家有所帮助。

    Xanthuim的博客地址:

    http://blog.csdn.net/qq_15003505

    前言

    最近在工作中使用到蓝牙的功能,当然我们这个蓝牙时跟蓝牙芯片结合使用的,而不是手机跟手机连接通信的。其实本质时差不多的,只是设备不一样罢了。在这里我不会贴出蓝牙那些协议等等复杂的名词解释,因为这个不是一两句话能解释的清楚,在我们先不太了解蓝牙的这些专业名词之前,我们先掌握它的基本使用就可以了,后续如果想深入了解的话,我们再花时间去学习。本文介绍的低功耗的蓝牙,是 Android 4.3 才开始支持的,而要使用传统蓝牙和高版本的蓝牙请参照官方文档,有中文介绍哦。

    官方蓝牙文档

    https://developer.android.google.cn/guide/topics/connectivity/bluetooth.html

    官方不同版本蓝牙示例(有3个):

    https://github.com/googlesamples?utf8=%E2%9C%93&q=bluetooth&type=&language=

    蓝牙基本使用流程

    从图上可以看出我这个例子只是单方面的通信,即手机只接收数据而不发送数据。

    蓝牙关键类

    BluetoothManager:蓝牙管理服务,如果对Android基本框架熟悉的话,你会发现蓝牙也属于最底层的驱动模块里,那么要使用蓝牙的东西就需要使用 (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE) 来获取了。不过看是把图贴一下。

    BluetoothAdapter:表示本地设备蓝牙适配器。 BluetoothAdapter 允许您执行基本的蓝牙任务,例如启动设备发现,查询已绑定(配对)设备的列表,使用已知MAC地址实例化 BluetoothDevice,并创建一个 BluetoothServerSocket 以监听来自其他设备的连接请求,并启动扫描蓝牙LE设备。这个类时关键类,后面会大量使用到它。

    BluetoothAdapter.LeScanCallback:用于提供LE扫描结果的回调界面。这个类就是扫描的回调接口,不过在 Android 5.0以上 使用抽象类 ScanCallback。

    BluetoothLeScanner:该类提供了对蓝牙LE设备执行扫描相关操作的方法。应用程序可以使用 ScanFilter 扫描特定类型的蓝牙LE设备。它还可以请求不同类型的回调来传递结果。不过这个类是在 Android 5.0(API21)以上才出现的,也就是对于Android 4.3的以上我们只会使用 BluetoothAdapter 来进行扫描等操作,当然如果是5.0以上的可以使用这个类来代替的。

    ScanCallback:蓝牙LE扫描回调,使用这些回调报告扫描结果。这个是抽象类与 BluetoothLeScanner 配套使用。

    BluetoothDevice:表示远程蓝牙设备,BluetoothDevice 允许您创建与相应设备的连接或关于它的查询信息,例如名称,地址,类和绑定状态。

    BluetoothProfile:配置文件代理。每个公共配置文件实现这个接口。它有几个直接子类,每个子类再不同场景中使用,如 BluetoothA2dp, BluetoothGatt, BluetoothGattServer, BluetoothHeadset, BluetoothHealth。在当前例子中使用到的是 BluetoothGatt。

    BluetoothGatt:该类提供蓝牙GATT功能,以实现与蓝牙智能或智能就绪设备的通信。后续使用该类做连接、断开、关闭等操作。

    BluetoothGattCallback:文档没有直接的解释,只说了被用在连接设备时候的回调。虽然文档没有详细说明,但是这个回调会在后续的连接、断开、通信中起到关键作用。

    好了,主要的几个类介绍的差不多了。接下来我们使用这几个类练习一下。

    1、获取蓝牙管理服务和适配器

    获取了适配器后,我们可以通过适配器是否为null来判断是否支持蓝牙功能(想必现在的手机应该都支持吧)。另外适配器还提供了以下的方法:

    上面的就是启用、关闭、扫描、停止的几个方法。需要注意的是在启用蓝牙的时候在不同手机会弹出启用对话框,比如魅族。那么这个时候你需要通过 isEnabled方法 来判断是否启用了,如果没有启用则使用 startActivity 来启用,然后通过 Activity 或者 Fragment 的 onActivityResult 回调方法来做余下的操作了。

    startActivityForResult(newIntent(BluetoothAdapter.ACTION_REQUEST_ENABLE),REQUEST_ENABLE);

    好了,使用上面的扫描方法就可以扫描到蓝牙设备了,是不是很简单啊。再说明一下,上面的 leScanCallback 就是上面提到的 BluetoothAdapter.LeScanCallback,你需要实现它就可以了。

    2、权限配置

    不过使用蓝牙也是要配置权限的,如果你没有在 Manifest 中配置,在 Android Studio 中使用上面的方法的时候它会报错要求你加入权限。我在这里列一下我使用到的权限:

    是的,你会发现使用蓝牙还需要位置权限?我开始也觉得一个蓝牙也要位置权限,后来在翻看官方文档的时候才知道的,不然你在5.0以上的手机上扫不出蓝牙的!详情请翻阅官方文档:

    https://developer.android.google.cn/guide/topics/connectivity/bluetooth-le.html#user-permission

    3、连接设备

    有了蓝牙设备后接下来我们连接下,然后发发数据看看。连接设备其实也很简单,就是通过扫描到的蓝牙设备对象来连接即可。蓝牙设备就是上面提到的 BluetoothDevice,这个类有一个方法:

    第一个 Context 就不说了;第二个参数 autoConnect 的解释是“是否直接连接到远程设备(false)或一旦远程设备可用即可自动连接(true)”;第三个参数也是上面提到的抽象类,这个类在连接过程中起到关键作用。最后方法会返回一个 BluetoothGatt 对象,后续我们通过这个对象可以重连、断开、关闭设备。贴下我例子中的连接方法:

    抽象类:

    这个类里面有很多方法,不过都被这个类实现了,我们根据自己的情况来重写。解释下上面列出的方法:

    onConnectionStateChange:监测蓝牙设备的连接、断开、读取设备信号强度值、发现服务(翻译的好别扭)。连接和断开可以通过 newState参数 来判断,注意是和 BluetoothProfile 的常量值来对比的,这个类也是上面提到过的。其实这个类提供了4个状态值,只不过在使用过程中只有 连接(状态值2)和 断开(状态值0),其他的没用到。

    至于后面的读取设备信号强度值、发现服务这两个分别用在获取信号强度和通信的。怎么解释?要知道蓝牙也是无线传输的,既然是无线就跟移动网、WIFI一样都存在信号强弱的情况,那么通过这个就可以获取了。信号强度值是负数,负数越大信号越好(最大理论值是0),单位是dBm。而发现服务,我们在成功连接后调用 gatt.discoverServices() 方法既可以获取与连接的设备进行通信了,最后回调 onServicesDiscovered 方法。

    onServicesDiscovered:这个方法里面我们需要做的就是使用蓝牙的 UUID 获取服务、特征、描述等对象,然后就可以给手机发送数据了。这里需要注意的是 UUID 不能随便写,而是设备厂商或者通用的 UUID,否则你是无法使用的。说到这个 UUID,其实我也比较迷惑的,很多文章在介绍 UUID 的时候都是一笔带过或者直接拿来用根本不解释这是干嘛的,而且也没找到一个比较全面介绍蓝牙协议等专业文档(谁找到了,麻烦给我留一个地址)。其实说到这,里面提到的特征、描述等对象,我也没详细去说请原谅。

    onCharacteristicChanged:远程特性通知,回调触发。就是上面执行完后,只要连接的设备触发某些动作(比如我的蓝牙芯片按钮按下、抬起),这个方法就会被调用了。然后我们在这个方法中就可以获取远程设备发过来的信息。

    好了,其实写到我这个例子基本的使用已经差不多了,剩下的无法就是蓝牙的断开、连接、关闭(释放资源)

    最后,贴下我的例子截图以及我使用的蓝牙芯片,是不是感觉高大上啊,哈哈~

    好了,我这个蓝牙芯片在连接之前的LED指示灯是一闪一闪的,而连接成功后就会常亮的。上图的3个按钮也是对应芯片的按键的。不够在这里说明一下,由于为了保密,我这里不会放出与蓝牙芯片的例子,而是单独写了一个简单的例子,不过底层的东西是不变的。另外这个是单方面的通信交互,如何做到双向通信呢?由于本例子只需要单向通信,所以就没涉及到,不够也是上面的例子的范畴,大家可以自己去研究下。另外说明下官方提供的低功耗的例子在使用“发现服务”的那个回调方法存在问题(连接了接收不到数据),我这里跟官方的例子还是不一样的。

    另外说明下,我的 Android Studio 版本是2.4 preview 3版本,对应的 gradle 版本是 gradle-3.4.1-all,所有低版本的自行修改配置。

    GitHub地址:

    https://github.com/Xanthuim/BluetoothSample

    文章原创作者GuoLin 书籍推荐

    郭林大神原创android 书籍:《第一行代码 android》

    淘宝链接: https://s.click.taobao.com/t?e=m%3D2%26s%3DgKUfuKdAZKocQipKwQzePOeEDrYVVa64K7Vc7tFgwiHjf2vlNIV67p2n%2BQBNMyE6Rku8%2Bpj6eJall3bs%2B3NRhNHnsKI%2BqxhyM0iVZhTFBom4YIorMPnmg8G0g2OJi%2FzmXHfenomYtn5EW9vzeG8LzfPUwktUBEmkxg5p7bh%2BFbQ%3D&pvid=10_106.6.161.154_3367_1490163222155

    相关文章

      网友评论

      • 冰川孤辰js:你好,请教一下: 1. 如何创建自定义的service/characteristic并让其他设备读取? 2. 如何写一个characteristic? 我使用mBluetoothGatt.writeCharacteristic(charac) 总是得到false, 不知道还有什么地方需要设置

      本文标题:Android之低功耗蓝牙的基本使用

      本文链接:https://www.haomeiwen.com/subject/jdtstxtx.html