Android 低功耗蓝牙开发简述

一、什么是低功耗蓝牙?

  低功耗蓝牙是在传统蓝牙的基础上开发的,但它与传统模块不同。最大的特点是降低了成本和功耗。可以快速搜索并快速连接。它保持连接并以超低功耗传输数据,低功耗蓝牙是专门针对基于物联网(IoT)设备构建的功能和应用程序设计的蓝牙版本。蓝牙BLE允许短期远程无线电连接并延长电池寿命。目前,蓝牙低功耗技术已被广泛使用,例如耳机、手环、电子秤、鼠标、键盘、灯、音箱等设备。

  蓝牙分为传统蓝牙和低功耗蓝牙。蓝牙4.0及更高版本被称为蓝牙低功耗,其中蓝牙4.0标准包括传统的蓝牙模块部分和蓝牙低功耗模块部分,这是双模式标准。在被蓝牙技术联盟采用之前,它是诺基亚设计的一种短距离无线通信技术,它的最初目标是提供最低功耗的无线标准,并且专门针对低成本,低带宽,低功耗而设计,并针对复杂性进行了优化。

二、怎么做低功耗蓝牙应用?

  在了解了低功耗蓝牙的基本知识之后,回到我们Android应用开发上来,你要做什么应用?你有没有好好想过呢?难道就是一句话:”干就完了!“,这是不可取的,因为你如果从来没有接触过那么你会在实际开发中遇到很多的问题,而这些问题都源于你的这句话:”干就完了!“。

  在做Android蓝牙应用时,要先确定几个问题,这能让你少踩几个坑。

  1. 之前有没有接触Android蓝牙开发?
  2. 蓝牙设备固件是公司自己的吗?
  3. 有没有蓝牙固件和蓝牙应用的文档和Demo?
  4. 具体的业务功能需求明确吗?
  5. Android端应用是重新写还是接手老项目?
  6. 应用是否需要上架?上架几个平台?

这些问题的答案就决定了你在开发Android低功耗蓝牙应用的进度和结果。

① 之前有没有接触Android蓝牙开发?

  做过和没做过是两种心态,虽然这个应用并不难,但是没做过一开始会像无头苍蝇一样,需要从网上获取相应的资料,还得是正确的资料才行。要先了解Android中各个版本对蓝牙的影响,API的使用。

② 蓝牙设备固件是公司自己的吗?

  做蓝牙应用是需要和设备打交道的,不是传统意义上的互联网App,属于物联网App,你的App甚至不需要使用网络,如果你只是做蓝牙通讯处理,没有数据需要上报到服务器的话。而蓝牙应用中最关键的就是蓝牙设备,这个蓝牙设备是否由你公司自行研发,是的话,你在开发过程中对接的时候相对轻松一些,不是的话你找技术支持了,也就是这个蓝牙设备固件的研发公司的技术支持人员和你对接来完成你的应用,这个就涉及到时间成本了,需要心里有数。

③ 有没有蓝牙固件和蓝牙应用的文档和Demo?

  这个问题就在于你是不是什么资料都没有,就让你开始做应用,然后还给你很短的开发周期,如果有资料和Demo的话可以边看资料边运行Demo,了解里面的各个API是怎么操作的,这样无论你是开发新的应用,还是就在这个Demo上进一步完善,加上自己的业务功能需求,都会比较简单一些。

④ 具体的业务功能需求明确吗?

  如果是需求摸棱两可,那么你在写代码的时候就需要做好框架设计封装,当然前提是你之前做过。蓝牙应用的框架设计主要在于数据交互,而数据交互的方式取决于蓝牙的通信协议。业务功能和这个协议也是息息相关的,例如你做电动牙刷和做手环就完全不一样。因此如果蓝牙设备的性质决定了你的应用业务功能的设计,当然你也不要指望功能需求定了就不改,那根本不存在。

⑤ Android端应用是重新写还是接手老项目?

  这个问题就在于你有没有背锅的风险,如果是接收老项目,你需要先运行一下,看看各个功能是否正常,项目中的代码都过一遍,看看有没有坑在里面。先花一段时间熟悉这个项目,然后再去做二次开发,并且做好你改动的地方的注释和说明,以后背锅的时候你还能挣扎一下。如果是新项目的话,你自己肯定最了解了,不过同样要设计好框架和做好注释说明,一个项目过一段时间你不去看它,再回过头来看,是需要重新熟悉起来的,有注释说明能帮你缩短熟悉的时间。

⑥ 应用是否需要上架?上架几个平台?

  上架应用有时候会比开发应用更麻烦,目前国内主流的应用市场也就是各大厂商的自带的应用市场,另外还有应用宝,百度应用市场这两个平台,如果你的应用需要上架,那么你需要提前申请软著,准备好资料,上架应用需要的资料还是比较多的,如果不出意外那也是你一个人独立完成。各个平台的开发者账号都不要自己去申请,用公司的账号或者邮箱,同时要注册企业开发者用户,很多平台个人开发者是无法上架应用的。目前来说我觉得上架应用市场时最麻烦的还是隐私政策,各个平台审核比以往要严格,各个平台又不太一样,注意隐私政策是需要在你们公司的官网上能看到的,需要一个链接地址。

三、做低功耗蓝牙应用的细节

  做蓝牙应用在Android上要了解这些内容。首先要扫描到蓝牙设备,这个地方你可以

① BluetoothLeScanner

  这个类提供对蓝牙 LE 设备执行扫描相关操作的方法。应用程序可以使用 ScanFilter 扫描特定类型的蓝牙 LE 设备。它还可以请求不同类型的回调来传递结果。

在这里插入图片描述

它里面主要就是启动扫描、停止扫描,以及扫描回调的处理,其中启动扫描的时候可以传入ScanFilter和ScanSettings,这两个参数的设置会对扫描结果造成影响,下面我们看看扫描回调。

② ScanCallback

扫描回调是一个抽象类,里面有三个回调方法,扫描结果,批量扫描结果,扫描错误。

在这里插入图片描述

一般来说你只需要实现处理onScanResult回调中ScanResult,这个类就是你所扫描到的信息。

③ ScanResult

这里面有扫描到的基本信息,内容比较多,看看它的组成。

在这里插入图片描述

参数:
device - 找到远程蓝牙设备。
eventType – 事件类型。
primaryPhy - 主要广告 phy。
secondaryPhy – 二级广告 phy。
advertisingSid– 广告集 ID。
txPower——发射功率。
rssi——接收到的信号强度。
periodAdvertisingInterval – 定期广告间隔。
scanRecord – 扫描记录,包括广告数据和扫描响应数据。
timestampNanos – 观察到扫描结果的时间戳。

这里面最常用的就是获取device,rssi。

  这里要注意一点,扫描蓝牙之前要做Android版本的判断,首先要判断手机蓝牙是否打开,而判断这个是否打开在Android12及以上需要先动态请求BLUETOOTH_CONNECT权限,权限通过后再通过系统蓝牙适配器去判断是否打开蓝牙开关。蓝牙打开之后要做定位权限的判断,Android12及以上则需要做BLUETOOTH_SCAN权限的请求,权限通过之后才能进行扫描,这里要注意会出现一些设备在Android12上获取BLUETOOTH_SCAN权限后也扫描不到,此时你需要再去请求定位权限,并且扫描权限这样设置一下:

	<uses-permission
        android:name="android.permission.BLUETOOTH_SCAN"
        android:usesPermissionFlags="neverForLocation"
        tools:targetApi="s" />

这个android:usesPermissionFlags你也可以尝试去掉,然后组合定位权限进行测试。

  当然了Android12中还有一个权限BLUETOOTH_ADVERTISE,一般情况你用不到它,这里需要了解一下蓝牙的扫描和发现的方式,为什么我们能扫描蓝牙扫描,而蓝牙设备连接之后就扫描不到了,是因为蓝牙设备再上电之后未被连接时一致处于广播状态,就是四处的广播自己这个设备的信息,比如常见的Mac地址,设备名称。这是一种无线电波,扫描的一方,通常为我们的手机,扫描这些广播通过NDK进行转化,回调到上层接收,你才能在ScanCallback中的回调中看到扫描到的蓝牙数据信息。这里扫描的一方作为主机,广播的一方作为从机,而如果要是手机也能够作为从机进行广播,则就需要请求这个权限,然后进行一些广播信息的配置,发送广播。

④ BluetoothGatt

  这个类在低功耗蓝牙通讯中至关重要,在通讯的各个环节都会涉及到BluetoothGatt,首先通过扫描到的蓝牙设备进行Gatt连接,参考这个方法。

在这里插入图片描述

  里面有三个参数,上下文,自动连接,gatt回调。这个方法的描述是这样的:(连接到此设备托管的 GATT 服务器。调用者充当 GATT 客户端。回调用于将结果传递给调用者,例如连接状态以及任何进一步的 GATT 客户端操作。该方法返回一个 BluetoothGatt 实例。您可以使用 BluetoothGatt 执行 GATT 客户端操作。)

因此我们获取BluetoothGatt 实例需要通过connectGatt()的方法,而不能通过new BluetoothGatt()的方式。

这里面又有一个很重要的抽象类BluetoothGattCallback。

⑤ BluetoothGattCallback

  作为一个抽象类,要实现里面的回调自然就需要一个实现类,然后重写父类的方法。进行回调的传递。connectGatt方法,会触发onConnectionStateChange回调方法,用来处理Gatt连接的状态改变,断开连接和异常状态都可以在这里进行处理。断连可以通过gatt.disconnect()进行,断连之后在回调中gatt.close();及时释放资源。

  发现服务是蓝牙通讯中很重要的一个环节,不同的蓝牙设备具备的服务不同,你可能从网络上看到一些例子,人家演示的时候很正常,然后你操作时就不正常,那是因为虽然是同一份代码,但是操作的蓝牙设备却不相同,所以发现服务就是很重要的,它可以让你知道你的设备支持那些服务,拥有那些特性,特性的描述又有那些。最顶级是服务,服务下面是特性,特性下面是描述,一个服务可能拥有多个特性,一个特性可能有多个描述,服务和特性及描述的uuid都是不同的。这些uuid各自的定义是不同的,首先要看是否服务SIG的标准蓝牙,另外是否有厂商自定义UUID。这一点你可以与做蓝牙固件的进行沟通。

  写入数据,由App写入数据到蓝牙设备中,可以通过gatt.writeCharacteristic()。这个写入时需要确定写入的服务是哪一个,写入的数据是有响应还是无响应,默认是有响应的,这里的有响应和无响应关系到写入数据的方式,例如你需要连续的传一段数据给蓝牙设备,开始指令,结束指令和中间数据,类似于开始和结束可以采用有响应的方式,而中间的数据传输可以采用无响应的方式,加快传输速度,无响应的方式速度快,但是是否写入成功无法保证,有响应速度慢,可以确认数据是否写入成功。区别类似发短信和打电话。然后通过characteristic.setValue(bytes),bytes就是要写入的数据。这是一个字节数组,这是字节数组的最大长度和MTU有关。

  获取MTU,蓝牙一般默认支持的MTU长度是23个字节,一个字节为类型操作码,两个字节为类型操作句柄,实际传输数据就是20字节。通过gatt.requestMtu(mtu)。会触发onMtuChanged回调。这里mtu 的范围在23 - 517之间,目前市面上Android版本高的手机基本上都是247。也就是说即使你mtu = 517,回调中的mtu可能还是247,为什么呢?因为你的Android手机上的蓝牙最大支持247。而在传输的时候你还需要-3,也就是244。单次传输的最大字节数据为244个字节。那么如果你有1000个字节需要进行传输,则需要对字节进行分包处理,例如一次最大传输244个字节,则需要分成5个包进行传输,前4个包,每个包为244个字节,最后一个包为24个字节。

  数据返回,输入数据时有一些指令设备是会返回数据的,设备返回的数据会在onCharacteristicChanged回调中出现,不过这个出现的前提是,你需要设置notify enable或者indicate enable。也就是一个写入描述的动作,通过gatt.writeDescriptor()进行,会触发onDescriptorWrite回调,在这个回调中你会知道你所设置的值是否生效,descriptor.getValue()获取具体的值。

在这里插入图片描述

  可以设置的参数就是这三个。这里还需要补充一个设置,那就是gatt.setCharacteristicNotification()这个设置,如果有一天固件说它返回了数据,而你在onCharacteristicChanged中并没有看到返回,同时你notify 已经enable了。那么你可以在onDescriptorWrite的回调中加上gatt.setCharacteristicNotification(),如果还收不到,那就是你的固件有问题。

这篇关于低功耗蓝牙开发应用的简述就先写到这里,如果有信息的内容也会补充到文章中的,山高水长,后会有期。

猜你喜欢

转载自blog.csdn.net/qq_38436214/article/details/126866948