Android低功耗蓝牙开发总结

Android之BLE(低功耗)蓝牙开发,kotlin开发安卓 } return bleUtil; } public void startBle() { if (!isStandByBle) { Toast.makeText(context, “该设备不支持蓝牙功能”, Toast.LENGTH_SHORT).show(); return; } bleDevices = new ArrayList<>(); BleScanRuleConfig scanRuleConfig = new BleScanRuleConfig.Builder() // 阅读详情

基础使用

权限申请

蓝牙权限在各个版本中略有不同

  • Android 12 及以上版本,如果不需要通过蓝牙来推断位置的话,蓝牙扫描不需要开启位置权
  • Android 11 及以下版本,蓝牙扫描必须开启位置权限
  • Android 9 及以下版本,蓝牙扫描可开启粗略位置权限
<!-- Android 12 及以上版本 -->
<!-- 如果明确不需要蓝牙推断位置的话,可以通过标记 usesPermissionFlags=“neverForLocation” --> 
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
  android:usesPermissionFlags="neverForLocation"
  tools:targetApi="s" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>

<!-- Android 11 及以下版本 -->
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30"/>

<!-- Android 9 及以下版本 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="28"/>

开启扫描/停止扫描

//获取蓝牙适配器
val bleAdapter = (context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager).adapter

//监听返回数据
private val bleScanCallback = object : ScanCallback() {
    override fun onScanResult(callbackType: Int, result: ScanResult?) {
        if (result != null){
            Log.e("bleLog", "startScanResult = $result")
        }
    }
}

/**
 * 开启扫描
 */
bleAdapter.bluetoothLeScanner.startScan(bleScanCallback)

/**
 * 结束扫描
 */
bleAdapter.bluetoothLeScanner.stopScan(bleScanCallback)

开始连接/断开连接


private var mBleGatt : BluetoothGatt? = null

//连接过程与数据接收回调
private val bleGattCallback = object : BluetoothGattCallback() {

  //连接状态变更
  override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {
    if (newState == BluetoothProfile.STATE_CONNECTED){
      //已连接
      //发现服务
      mBleGatt?.discoverServices()
    }else if (newState == BluetoothProfile.STATE_DISCONNECTED){
      //已断开连接
    }
  }

  //发现服务回调
  override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
    // 调用 mBleGatt?.discoverServices() 时触发该回调
    if (status != BluetoothGatt.GATT_SUCCESS){
      //失败
      return
    }
    //获取指定GATT服务,UUID 由远程设备提供
    val bleGattService = mBleGatt?.getService(UUID.fromString("8888888"))
    //获取指定GATT特征,UUID 由远程设备提供
    val bleGattCharacteristic = bleGattService?.getCharacteristic(UUID.fromString("777777"))
    //启用特征通知,如果远程设备修改了特征,则会触发 onCharacteristicChange() 回调
    mBleGatt?.setCharacteristicNotification(bleGattCharacteristic, true)
    //启用客户端特征配置【固定写法】
    val bleGattDescriptor = bleGattCharacteristic?.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"))
    bleGattDescriptor?.value = BluetoothGattDescriptor.ENABLE_INDICATION_VALUE
    mBleGatt?.writeDescriptor(bleGattDescriptor)
  }

  //启用客户端特征配置结果回调
  override fun onDescriptorWrite(gatt: BluetoothGatt?, descriptor: BluetoothGattDescriptor?, status: Int) {
    if (status == BluetoothGatt.GATT_SUCCESS ){
      //此时蓝牙设备连接才算真正连接成功,即具备读写数据的能力
    }
  }

  //App修改特征回调,即 App 给设备发送数据结果回调
  override fun onCharacteristicWrite(gatt: BluetoothGatt?, characteristic: BluetoothGattCharacteristic?, status: Int
                                          ) {
    if (status == BluetoothGatt.GATT_SUCCESS){
      //数据写入完成
      // 调用 characteristic?.value 得到的 ByteArray 与 发送数据一样
    }
  }

  //远程设备修改特征描述回调,即设备给 App 发送数据
  override fun onCharacteristicChanged(gatt: BluetoothGatt?, characteristic: BluetoothGattCharacteristic?
      ) {
    //调用 characteristic?.value 获取远程设备发送过来的数据
  }
}

/**
 * 开始连接
 * @param deviceMac 设备Mac地址
 */
val bleDevice = bleAdapter.getRemoteDevice(deviceMac)
mBleGatt = bleDevice.connectGatt(context, false, bleGattCallback, BluetoothDevice.TRANSPORT_LE)

/**
 * 断开连接
 */
mBleGatt?.disconnect()
mBleGatt?.close()

写入数据

mBleGattCharacteristic?.value = data
mBleGatt?.writeCharacteristic(mBleGattCharacteristic)

完整链路

总结

记住一个核心:蓝牙传输非常不稳定,指不定啥时候就没响应或丢包了。

连接过程

用户体验

  • Android 12 以下版本蓝牙扫描需要开启定位+授权才能使用,所以在扫描前要申请蓝牙&定位权限+判断是否开启蓝牙&定位。
  • 使用过程中,用户可能误操作关闭蓝牙,所以要监听蓝牙开关状态。
  • 蓝牙扫描添加超时机制,超时自动停止扫描。
  • 如果用列表按照信号强度展示扫描结果,建议扫描结束后再让用户选择设备,防止列表频繁跳动,导致用户误选。
  • 关于蓝牙的UI界面或操作,都需要判断当前蓝牙是否已连接。

注意点

  • 连接过程会有很多中间过程(触发连接 -> 连接回调成功后 -> 发现服务 -> …),当获取为 null 或者返回失败时,要做异常返回,防止进度卡死。
  • 同上,连接中间过程较多,防止远端设备偶现无响应,在连接过程中设置超时机制,超时判定连接失败。
  • 当存在多个 GATT 特征时,可能需要调用多次 setCharacteristicNotification() + writeDescriptor(),注意此操作不能连续调用,正确姿势:gatt1 调用完成,待 onDescriptorWrite() 回调后,gatt2 再调用。

数据收发过程

背景:我手里的远端设备是一款实时操作系统的智能穿戴设备。该设备有一个特点:只能处理一条指令,处理完成后等待下一条,如果同时来多条,则只能处理第一条。

注意点

  • 因为远端设备只能处理单条指令,所以需要维护一个优先级队列
  • 蓝牙传输有最大传输单元限制(MTU),默认最大 23 个字节,可用的只有 20 个字节,[ 23 byte(ATT) =1 byte(Opcode) + 2 byte(Handler) + 20 byte(BATT) ],所以在发送指令时要做分包处理。
  • MTU 可通过调用 requestMtu() 调整大小,具体调整多大需和远端设备协定,调用后会回调 gattCallback#onMtuChanged(),注意:发现服务的调用要在该回调中,不能在连接状态回调中。
  • 单一指令发送和回包,需要加超时机制。即调用发送指令时开始超时倒计时,当触发 onCharacteristicChanged() 时并判断为指令回包,则移除倒计时。如果 onCharacteristicWrite() 返回失败或超时未回包,则移除倒计时并返回失败。
  • 单一指令发送并伴随多条回包,需要加 watchDog 机制。即调用发送指令时开始“养狗”,当有远端设备回包时“喂狗”,回包全部完成时“杀狗”,如果 onCharacteristicWrite() 返回失败或到时间没有“喂狗”,则“杀狗”并返回失败。

可能用到的知识

进制转换

Android Studio 打印日志或断点时,会自动将 16 进制 转成 10 进制进行显示。

十进制 与 16进制
十进制 -> 16进制:

十进制数 除以 16 取余,然后从低往上输出。例如:1758 = 0x6DE

16进制转 -> 十进制:

位数指向的数 * 16^位数 相加之和。例如 0x2A7F = 10879

十进制 与 二进制
十进制 -> 二进制:

记住常用数转化:例如, 45 = (32 + 8 + 4 + 1) = 101101

十进制二进制
1 (2^0)01
2 (2^1)10
4 (2^2)100
8 (2^3)1000
16 (2^4)10000
32 (2^5)100000
64 (2^6)1000000
二进制 -> 十进制:

位数指向的数 * 2^位数 相加之和。例如 10010 = 18

16进制 与 二进制
16进制 -> 二进制:

按每位数单独转二进制。例如: 0x6DA2 = 110110110100010

二进制 -> 16进制:

每四位一组,每组转 16 进制,然后拼接。例如: 101010110 = 0x156

位运算
& (与)

都为 1 时才是1

|(或)

**只要有 1 **时就是 1

^ (异或)

**只有一个 1 **时才是 1

~ (取反)

1 变 0, 0 变 1

>> (右移)

除以2^右移位数。例如: 75 >> 3 = 9

<< (左移)

乘以 2^ 左移位数。例如: 75 << 3 = 600

推荐阅读

Android 12 中的新蓝牙权限
蓝牙概览 | Connectivity | Android Developers
蓝牙智能设备数据采集平台化方案 | 京东云技术团队 - 掘金
BLE低功耗蓝牙技术详解
Android蓝牙通信机制详解 - 掘金





Hi,我是“青杉”,您可以通过如下方式关注我:

Android - 蓝牙开发 文章目录科普SIG类型制式编程Classic BluetoothBluetooth Low Energy蓝牙的UUID是什么?有什么用? 科普 https://zh.wikipedia.org/wiki/%E8%97%8D%E7%89%99 蓝牙(英语:Bluetooth),一种无线通讯技术标准,用来让固定与移动设备,在短距离间交换资料,以形成个人局域网(PAN)。其使用短波特高频(UHF)无线电波,经由 2.4 至 2.485 GHz 的 ISM(工业、科学、医疗)频段来进行通信。1994 年由电信商 阅读详情

相关推荐

Android低功耗蓝牙(BLE)开发(一)

BLE是指低功耗蓝牙(Bluetooth Low Energy),也被称为蓝牙4.0。它是蓝牙技术的一种变体,旨在消耗更少的电量,具有便携性,并且可以在无线传输距离较短的范围内实现低速数据传输。BLE技术已经广泛应用于智能家居、健康监测、物联网等场景中。

king的专栏 3853

Android 蓝牙开发(一)

蓝牙是一种短距离无线通信技术,我们相对熟悉的移动端设备短距离通信技术有NFC红外蓝牙;NFC:主要应用于操作简单,即时相应的刷卡红外:主要应用于需要按键控制,例如家电遥控蓝牙:主要用于两部设备之间复杂且大量的数据传输(这里又分为低功耗蓝牙和经典蓝牙)今天小编给大家分享的是经典蓝牙。

Ai1114的博客 1万+

Android低功耗蓝牙开发

1。对于安卓12+的机型来说,想要搜索附近附近周围蓝牙设备,需要动态授权以下权限2.在AndroidManifest文件配置时,如果想不申请定位权限就能搜索到设备,必须在BLUETOOTH_SCAN权限上加上android:usesPermissionFlags="neverForLocation",否则仍需申请定位权限ACCESS_FINE_LOCATION。不然,如果不加上面这段代码,还需申请一下位置权限。

m0_62821106的博客 1030

Android蓝牙功能开发(低功耗与经典)

Android 蓝牙开发,很多项目会使用到,自己去摸索封装或者引用其他框架,也能解决部分问题。为何说是部分问题,Android蓝牙分为低功耗版与经典版,经典版是可以直接选择即可实现链接,低功耗版是需要配置uuid。故推荐一个框架,下面来分享使用教程。分两部分第一部分是直接使用框架,第二部分是修改框架源码,使用哪一种方式可以结合自己的需要。Android开发建议使用Android蓝牙调试工具app初步调试使用,这里推荐BLE调试助手app,各大应用市场都可以下载。BLE调试助手首页展示。

shi450561200的博客 7180

Android BLE低功耗蓝牙开发

Android蓝牙开发前,首先要区分是经典蓝牙开发还是BLE(低功耗)蓝牙开发,它们的开发是有区别的,如果还分不清经典蓝牙和BLE(低功耗)蓝牙的小伙伴,可以先问问度娘。 开发流程: 开启蓝牙 扫描蓝牙 配对蓝牙 连接蓝牙 通信 1.先获取蓝牙的服务对象 private BluetoothManager bluetoothManager(Context context) { ...

zwq_c的博客 489

Android之BLE(低功耗)蓝牙开发,安卓rxjava使用

// private String uuid_characteristic_send = “自己获取的”; private boolean isStandByBle; private boolean isEnableBle; private Context context; private Handler handler = new Handler(Looper.getMainLooper()); private final int START_SCAN = 100; private final in

m0_64603776的博客 479

Android 低功耗蓝牙开发简述

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

晨曦 5948

Android蓝牙开发(二) BLE4.0低功耗蓝牙

一、BLE4.0低功耗蓝牙 Bluetooth Low Energy,蓝牙低功耗,是从蓝牙4.0开始支持的技术。相较传统蓝牙,传输速度更快、覆盖范围广、安全性高、延时短、耗电低等特点。 二、关键术语 1.GATT(通用属性配置):通用属性配置文件,用于ble链路上发送和接收“属性”的数据块。目前所有的ble应用都是基于GATT的,一个设备可以实现多个配置文件。 2.ATT(属性

Near的博客 6205

Qt for Android 安卓低功耗蓝牙(BLE)开发环境搭建

因为涉及到低功耗蓝牙(BLE),搭建能自动弹框获取定位权限的Qt6 for Android开发环境。

abc6781的专栏 2129

Android 低功耗蓝牙开发(扫描、连接)

由于本文罗列的知识点是根据我自身总结出来的,并且由于本人水平有限,无法全部提及,欢迎大神们能补充~将来我会对上面的知识点一个一个深入学习,也希望有童鞋跟我一起学习,一起进阶。提升架构认知不是一蹴而就的,它离不开刻意学习和思考。**这里,笔者分享一份从架构哲学的层面来剖析的视频及资料分享给大家,**梳理了多年的架构经验,筹备近1个月最新录制的,相信这份视频能给你带来不一样的启发、收获。,第一时间获取最新知识点Android架构师之路很漫长,一起共勉吧!

2401_84123094的博客 1038

Android 低功耗蓝牙开发与遇到的坑

过程 搜索-配对-连接-通信 目前配对的环节可以省略了 1.搜索:我是传统的蓝牙搜索➕低功耗蓝牙搜索一起使用的 经典蓝牙:调用 mBluetoothAdapter.startDiscovery(); 这时我们需要注册一个通知来监听回调 完整代码如下: /** * 普通设备搜索 */ public void searchDevices() { try { ...

小白新人 2030

android 低功耗蓝牙,Android 低功耗(BLE)蓝牙开发说明

BLE(Bluetooth Low Energy)低功耗蓝牙兴起的原因BLE蓝牙的兴起主要是因为可穿戴设备的流行,由于传统蓝牙不能满足可穿戴设备的续航要求,因此大部分可穿戴设备采用蓝牙4.0技术,即BLE蓝牙技术。BLE的特点快速搜索、快速连接、超低功耗连接和数据传输,但是数据传输速率低。在Android开发中,BLE蓝牙一包数据最多20个字节,因此在Android系统下最好不要使用BLE蓝牙传输...

weixin_42332910的博客 578

Android 蓝牙——概述(一)

Profiles (蓝牙应用规范),它从应用场景的角度为蓝牙技术的使用制定了不同的规范。这也是和大众日常生活接触最多的一部分。蓝牙支持很多Profiles:MAP:(MessageAccessProfile),短信访问协议,允许设备间的信息交换,短信。使用场景:智能车载中同步短信等信息。HFP:(Hands-free Profile),电话免提协议,让蓝牙设备(如蓝牙耳机/车机)可以控制电话,如接听、挂断、拒接等。

小旭的专栏 3491

Android关于低功耗的蓝牙开发工具类

前段时间公司一直在做与蓝牙通讯的项目,蓝牙在网络上有很多资料,发现有些地方还是有些讲述不具体的地方,所以决定总结一下。蓝牙低功耗通讯的工具类使用方法。        蓝牙通讯之中最重要的就是uuid,因为其他的信息都可以通过扫描之后获得。唯有uuid是需要开发者填写进去的交流的双方约定唯一的“钥匙”。        uuid可以理解为端口,基本上分为三种,发送数据的uuid,接收数据的uuid

weixin_30267253的博客 698

第5.1节 构网控制:电压源特性与电压调节

摘要: 构网型变流器的核心物理本质是作为可控交流电压源,通过戴维南等效模型(受控电势源+低输出阻抗)自主建立并调节电压,增强电网电压刚度。其电压调节通过无功-电压闭环控制实现,内环为自动电压调节器(AVR),外环为无功-电压下垂特性,模拟同步发电机功能。关键技术包括自适应增益、虚拟阻抗补偿及动态限流策略,以应对弱电网稳定性、故障过流等问题。该设计满足《规范》对电压调节范围、动态无功支撑的要求,是高比例新能源电力系统电压稳定的关键解决方案。

技术工作者 1106

【华为鸿蒙3.0/荣耀安卓12使用VMOS Pro的激活方式】

解压激活工具 →连接数据线 轻松搞定激活!

Amy_mumu的博客 142万+

Android开发——低功耗蓝牙通信BLE

1.前言 接着上一章传统蓝牙通信,现开发低功耗蓝牙通信,低功耗蓝牙相比于传统蓝牙有以下区别 1.传统蓝牙用于传输数据量大的(音乐),低功耗蓝牙用于传输量小的(手环) 2.低功耗蓝牙功耗低 。。。。。 多了Service还有Characteristic...

daguniang123的博客 1083

【ECCV 2024】动态范围直方图自注意力DHSA,即插即用!

直方图自注意力机制,将空间特征按强度分段并进行分组,然后在各个分组内或分组间应用自注意力,以选择性地关注具有动态范围的空间特征,并处理长距离内相似退化的像素。

qq_43303160的博客 1844

【Android】蓝牙开发——BLE(低功耗蓝牙)(附完整Demo)

之前的几篇文章,主要介绍了经典蓝牙开发相关的知识,今天我们就来看看低功耗蓝牙的开发。如果小伙伴们对之前的文章感兴趣兴趣,也可以看看,欢迎提出不足或者建议。【Android】蓝牙开发——经典蓝牙(附Demo源码)【Android】蓝牙开发——经典蓝牙配对介绍(通过手机系统蓝牙演示)【Android】蓝牙开发—— 经典蓝牙配对介绍(Java代码实现演示)附Demo源码BLE,全称 Bluetooth Low Energy,即低功耗蓝牙。

一个IT人的技术成长历程。 5701

手把手教你用gym训练宇树GO2机器人模型(附完整配置文件)

本文提供了一份详细的实战指南,教你如何使用Gym框架为宇树GO2四足机器人搭建强化学习训练环境。文章深入解析了环境配置、参数调试、奖励函数设置等关键步骤,并分享了避开常见陷阱的经验,旨在帮助开发者高效完成模型训练。

oo7890的博客 321

解决WSL2网络隔离:Ubuntu子系统共享Windows代理的3种方法

本文详细解析了WSL2的网络隔离特性,并提供了三种在Ubuntu子系统中共享Windows代理的实用方法:环境变量法、配置文件法和系统服务法。通过具体代码示例和方案对比,帮助开发者快速解决WSL2网络访问问题,实现一键设置代理,提升开发效率。

weixin_29295541的博客 450

Android 蓝牙开发(三) -- 低功耗蓝牙开发

前面已经学习了经典蓝牙开发,学习了蓝牙的配对连接和通信,又通过 配置 A2DP 文件,实现手机和蓝牙音响的连接和播放语音。 这篇,我们来学习蓝牙开发的最后一章,低功耗蓝牙 BLE,也就是我们常说的蓝牙 4.0 。 今天要完成的效果如下: 中心设备 外围设备 一. 简介 与传统蓝牙不同,低功耗蓝主要为了降低设备功耗,支持更低功耗(如心率检测仪,健身设备)等设备进行通信。 Android 在 4.3(API 18) 后将低功耗蓝牙内置,并提供对应的

夏至的稻穗的博客 5784

SDM660电源部分配置:

SDM660电源部分配置: Panel power supplies 1、Reference power supplies Description Name Regulator Voltage (V) Panel power supply 0 vddio PMIC 660/L11 1.8 Panel power supply 1 Lab PMIC 660/lab 4.6 Panel power s...

weixin_41811215的博客 4727

Android Ble低功耗蓝牙开发

BLE设备的角色(中央设备或外围设备)通常取决于设备的功能和用途。通过定义不同的服务和特征值,设备可以提供不同的功能和操作,如传感器数据、控制命令等。中央设备(Central):可看作是客户端,中央设备通常是具备计算能力和连接性的设备,例如智能手机、平板电脑或计算机。简化的协议栈:BLE采用了简化的协议栈,包括L2CAP(逻辑链路控制与适配协议)、ATT(属性协议)和GATT(通用属性配置文件)。通过BLE广播,设备可以宣布自身的存在、提供基本的信息和服务,以便其他设备发现和与之进行进一步的通信。

qq_26867067的博客 628

工业级越界行为识别数据集:YOLOv8/v9直接训练的围栏异常检测资源

越界行为识别是智能安防与工业安全中的基础视觉任务,其核心在于对人员、车辆等目标跨越物理边界(如围栏、警戒线、作业禁区)的精准检测与分割。该技术依赖于高质量实例分割标注、归一化坐标格式及场景鲁棒性设计,具备低延迟、高召回、强泛化等工程价值,广泛应用于智慧工地电子围栏、化工厂禁区告警、物流园区越界监控及变电站安全巡检等真实工业场景。本数据集以YOLOv8/v9为基准构建,提供万张实拍+合成图像、像素级Segmentation标注、分层划分与完备元数据,开箱即用,直击工业落地中数据清洗、格式转换与标注不一致等关键

weixin_30080745的博客 316

【异常】Cursor编辑器 “Taking longer than expected...“ 报错全链路排查与解决方案

该提示并非传统的程序崩溃或语法报错,本质是Cursor编辑器的超时预警机制——当核心任务(云端AI推理请求、本地项目索引等)的执行耗时超出系统预设阈值时,触发的用户告知类提示,核心诱因是任务执行全链路出现阻塞或性能瓶颈。以下方案按排查优先级从高到低排序,覆盖从快速急救到根因根治的全流程,可按步骤逐步验证解决。针对大仓库、多依赖项目的索引超时问题,核心是通过规则过滤无效文件,从根源降低索引负载。

奶爸的编程之路,也就一周冷个三天 3099
上一篇: Flutter 混合开发 - 动态下发 libflutter.so & libapp.so
下一篇: Flutter 混合开发 - aar打包
青杉`
博客等级 码龄10年 148粉丝 39原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值