android 蓝牙ble app开发(二) -- 关键概念,连接参数,连接请求

本文介绍了BLE蓝牙开发中涉及的关键概念,如连接事件、超时时间、连接间隔等,并探讨了如何更新连接参数,同时对比了Android与iOS平台的兼容性和差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

android  蓝牙ble app开发中 经常会遇到很多问题,这个时候就需要用到抓包软件进行分析,单单从现象上很难鉴定是设备固件端的问题,还是我们自己app写的不对的问题。这一点是做android的是比较纠结的,因为固件端经常是和ios通信没毛问题,android问题偶尔,这个偶尔很经常出现。(固件基于cc2540 2541)

这篇记录的内容是android app开发时遇到的,但是本身的内容却是ble协议的一些内容,ios 也是一样的下一篇会记录下抓包过程与分析。

1、知识储备:

要分析ble蓝牙包 需要懂一些ble蓝牙协议栈的内容,和一些核心概念。

最关键的几个概念

Connection Events:连接事件

这个概念比较抽象,之前看了很多解释不明白,ti 宣讲会上讲ppt讲的很清楚

简单的说就是通信建立在连接事件上,每次连接事件时才是真正的通信事件,其余时间时休眠的(低功耗)

对应在程序上就是如果连接间隔的时间设置的大于 通信间隔,就会出现数据通信不流畅,没有接收到周期性数据,数据一卡顿一卡顿时而没有时而很多


Supervision Timeout:超时时间(在这个时间内没有接收到响应就会断开)

Slave Latency:这个不好翻译,看图最实在了

理解成可以忽略的空白响应数吧


Connection Interval:连接间隔


简单的理解成连两个连接事件之间的间隔时间呗


另外还有:Advertisement InterVals 广播间隔,和名字一个意思


2、关于更新连接参数

ConnectionParameter Update Request

有阅读蓝牙协议栈和一些材料,简单的说就是主机决定连接参数的值( connection interval, slave latency, timeout),从机可以请求更新这些参数,主机决定是不是接受,接受的值是多少。所以是会出现手机接受参数后和从机请求的参数有偏差,或者甚至是拒绝(ios)。

这里不得不提到:android 和 ios  的ble开发与兼容不是一个等级。

相同点:android 和 ios 都是在手机和设备建立连接时就会默认设置这些参数,app开发是无法修改这些参数的,这些默认参数由手机厂商决定。

不同点:当产品基于功耗等的考虑是应该要修改这些参数的,都是由从机提出更新申请,ios 有保护机制当从机给的参数超过它的范围它会拒绝这些不合理参数,然后使用默认值。而android 目前(4.3 4.4)是都会接受从机的更新参数,即使不合理。这里就会照成一种 设备通信 ios可以  android出问题 而且android即使接受参数并且使用这些参数更新后还会出现和参数不和的现象,典型的就在这个timeOut上,是会比更新请求里的timeOut长而且不同手机长的时间不一样。ios 好像是长5秒


ios 的参数范围还是很有参考价值的,不然在这个范围外,ios拒绝了 ,android接受了问题就蛋疼了。

Ti 问题网站上是这么回复的ios ble参数范围:http://www.deyisupport.com/question_answer/wireless_connectivity/bluetooth/default.aspx 这上面找具体哪个帖子没记录

The connection parameter request may be rejected if it does not comply with all of these rules:

Interval Max * (Slave Latency + 1) ≤ 2 seconds

Interval Min ≥ 20 ms   

Interval Min + 20 ms ≤ Interval Max

Slave Latency ≤ 4

connSupervisionTimeout ≤ 6 seconds

Interval Max * (Slave Latency + 1) * 3 < connSupervisionTimeout

注:ble协议里interVal   的范围是7.5ms - 32s 


3、android连接参数的补充

ble 协议里主机是对连接参数的绝对设置权,从机只能提出更新请求是否被接受是主机决定。

手机app开发里是不存在修改这个值的api的,至少4.3 4.4 没见到,5.0不知道。BlueDroid的android ble栈源码是驱动级的,即使改了,也没用,要重新改手机的驱动文件,我是这么理解的,也不知道对不对


另外在做android ble OAD 在线更新固件时,阅读TI的sensorTag 的源码时发现它里面有个 CC_SERVICE_UUID 服务可以设置OAD连接参数。而这个连接参数修改了也就修改了我们的固件的连接参数。参看ti 的回答:

The connection control service is a separate service, and can be added by adding ccservice.c/h from Profiles/SensorProfile/. Have a look in the SensorTag project to see how it's added to the GATT server and otherwise used.

ti 的demo里有这个cc服务的添加方法,虽然和他们的回答方法不大一样,添加后确实能实现app更改更新参数的目的。


cc服务的流程也比较清晰,android主机告诉ble固件我要更新参数参数是什么什么,然后固件拿着这个参数来进行更新参请求,adnroid设备再把这个请求设成此次通信的连接参数。这个和前面所描述的android手机app开发没有主动设置连接参数的api没有矛盾,它是通过高数ble从机,从机提出更新,再完成更新确认



4、补充附件

有一些朋友像我讨要这份ti 宣讲的ppt,附在这里: http://download.csdn.net/download/lckj686/9998176

<think>我们正在开发一个Android应用程序,需要实现扫描维码并连接BLE蓝牙设备的功能。根据引用内容,我们可以将任务分解为两个主要部分:扫描维码和连接BLE设备。 ### 步骤1:扫描维码 使用Android的CameraX API或ZXing库实现维码扫描功能。这里推荐使用ZXing库,因为它成熟且易于集成。 1. 在`build.gradle`中添加依赖: ```groovy implementation 'com.journeyapps:zxing-android-embedded:4.3.0' ``` 2. 在需要扫描的地方启动扫描活动: ```java IntentIntegrator integrator = new IntentIntegrator(activity); integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE); integrator.setPrompt("扫描维码"); integrator.setCameraId(0); // 使用后置摄像头 integrator.setBeepEnabled(false); integrator.setBarcodeImageEnabled(true); integrator.initiateScan(); ``` 3. 在`onActivityResult`中获取扫描结果: ```java @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data); if (result != null) { if (result.getContents() == null) { // 扫描取消 } else { String qrContent = result.getContents(); // 处理扫描结果,qrContent应该包含BLE设备的MAC地址 } } else { super.onActivityResult(requestCode, resultCode, data); } } ``` ### 步骤2:连接BLE设备 扫描维码后,我们得到BLE设备的MAC地址,然后进行连接。根据引用[1]和[2],连接BLE设备需要以下步骤: 1. 获取`BluetoothAdapter`和`BluetoothDevice`: ```java BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); BluetoothDevice device = bluetoothAdapter.getRemoteDevice(macAddress); // macAddress从维码获取 ``` 2. 使用`BluetoothGatt`连接设备: ```java BluetoothGatt bluetoothGatt = device.connectGatt(context, false, gattCallback); ``` 3. 实现`BluetoothGattCallback`处理连接状态和数据: ```java private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { if (newState == BluetoothProfile.STATE_CONNECTED) { // 连接成功,发现服务 gatt.discoverServices(); } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { // 连接断开 } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { // 发现服务,可以获取特征值并启用通知 enableNotification(gatt); } } // 其他回调方法... }; ``` 4. 开启通知(根据引用[2]): ```java private void enableNotification(BluetoothGatt gatt) { BluetoothGattService service = gatt.getService(SERVICE_UUID); if (service != null) { BluetoothGattCharacteristic characteristic = service.getCharacteristic(CHARACTERISTIC_UUID); if (characteristic != null) { // 设置通知 gatt.setCharacteristicNotification(characteristic, true); BluetoothGattDescriptor descriptor = characteristic.getDescriptor(DESCRIPTOR_UUID); if (descriptor != null) { descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); gatt.writeDescriptor(descriptor); } } } } ``` ### 注意事项 - 权限:需要蓝牙和位置权限(Android 6.0+需要位置权限用于扫描BLE设备)。 - 异步操作:BLE操作是异步的,需要在主线程中处理回调。 - 连接管理:连接后需要管理连接状态,并在不需要时断开连接以节省电量。 ### 整合流程 1. 用户扫描维码,获取BLE设备的MAC地址。 2. 使用该MAC地址连接BLE设备。 3. 连接成功后,发现服务并启用通知。 4. 在UI上显示连接状态和数据。 §§相关问题§§ 1. 如何优化BLE连接以降低功耗? 2. 在Android中如何处理BLE连接的重连机制? 3. 维码扫描除了ZXing库,还有哪些推荐的库?</think>### Android Studio开发:扫描维码连接BLE蓝牙设备应用程序 #### 一、整体架构 ```mermaid graph TD A[启动应用] --> B[扫描维码] B --> C{解析维码内容} C -->|成功| D[获取BLE设备MAC地址] C -->|失败| B D --> E[停止扫描] E --> F[连接BLE设备] F --> G{连接结果} G -->|成功| H[启用特征通知] G -->|失败| B ``` #### 关键实现步骤 1. **维码扫描集成** ```groovy // build.gradle 添加依赖 implementation 'com.journeyapps:zxing-android-embedded:4.3.0' ``` ```java // 启动维码扫描 new IntentIntegrator(activity) .setDesiredBarcodeFormats(IntentIntegrator.QR_CODE) .setPrompt("扫描设备维码") .setCameraId(0) // 后置摄像头 .initiateScan(); // 处理扫描结果 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data); if (result != null && result.getContents() != null) { String macAddress = parseMacAddress(result.getContents()); // 从维码提取MAC connectToBleDevice(macAddress); } } ``` 2. **BLE连接核心实现** ```java // 连接BLE设备 private void connectToBleDevice(String macAddress) { BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); BluetoothDevice device = adapter.getRemoteDevice(macAddress); // 使用异步连接避免阻塞UI线程[^2] bluetoothGatt = device.connectGatt(this, false, gattCallback); showLoading(); // 显示连接加载动画[^1] } // BLE回调处理 private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { if (newState == BluetoothProfile.STATE_CONNECTED) { gatt.discoverServices(); // 发现服务 } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { runOnUiThread(() -> showError("设备已断开")); } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { enableNotifications(gatt); // 启用特征通知 } } }; // 启用通知[^2] private void enableNotifications(BluetoothGatt gatt) { BluetoothGattService service = gatt.getService(SERVICE_UUID); BluetoothGattCharacteristic characteristic = service.getCharacteristic(CHARACTERISTIC_UUID); gatt.setCharacteristicNotification(characteristic, true); BluetoothGattDescriptor descriptor = characteristic.getDescriptor(DESCRIPTOR_UUID); descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); gatt.writeDescriptor(descriptor); } ``` 3. **权限配置 (AndroidManifest.xml)** ```xml <uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <!-- Android 12+ 需要 --> <uses-permission android:name="android.permission.CAMERA"/> <!-- BLE特性声明 --> <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/> ``` #### 三、优化建议 1. **连接超时处理** ```java // 添加30秒连接超时 handler.postDelayed(() -> { if (!isConnected) { bluetoothGatt.disconnect(); showError("连接超时"); } }, 30000); ``` 2. **错误处理增强** ```java @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { if (status != BluetoothGatt.GATT_SUCCESS) { Log.e("BLE", "服务发现失败: " + status); // 实现重试逻辑或错误上报 } } ``` 3. **低功耗优化[^2]** - 连接后降低扫描频率 - 适时进入`BluetoothGatt.REQUEST_MTU`协商优化包大小 - 使用`gatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_LOW_POWER)` #### 四、常见问题解决 1. **Android 12+权限变更** ```java // 需要动态请求新权限 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { requestPermissions(new String[]{ Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT }, REQUEST_CODE); } ``` 2. **后台连接限制** - 使用前台服务维持连接 - 在`onPause()`中降低连接优先级 - 使用`WorkManager`处理重连
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值