以下内容是在原先 Windows 平台开发流程的基础上,补充针对 Android 平台开发同时支持 SPP(经典蓝牙)和 BLE(低功耗蓝牙)透明传输设备的思路与步骤,帮助你在 Android 上完成相关功能的实现。请根据你的技术栈(Java/Kotlin、开发工具、API Level 等)和项目需求进行调整。
一、Android 平台概览
在 Android 上进行蓝牙开发主要分为两部分:
- 蓝牙经典(BR/EDR),也就是常说的 SPP(Serial Port Profile)方式。
- 适用于 Android 2.0 起几乎所有版本,且系统原生支持 SPP 协议栈。
- 在 Android 中通过 BluetoothAdapter、BluetoothDevice、BluetoothSocket 等类实现。
- 低功耗蓝牙(BLE),使用 GATT 协议进行特征(Characteristic)的读写、订阅通知(Notification/Indication)等。
- Android 4.3 及以上开始支持 BLE(API Level 18+)。
- 在 Android 中通常结合 BluetoothLeScanner、BluetoothGatt、BluetoothGattService、BluetoothGattCharacteristic 等来实现。
需要注意:
- 从 Android 6.0(API 23)开始,蓝牙扫描需要定位权限。
- 从 Android 10(API 29)开始进一步收紧权限,需要精确位置信息权限来扫描 BLE 设备。
- Android 12(API 31)及之后新增 Bluetooth 权限(BLUETOOTH_SCAN、BLUETOOTH_CONNECT 等),需要在 Manifest 中声明并在运行时请求权限。
二、SPP(经典蓝牙)开发流程
-
打开蓝牙与获取权限
- 检查并打开蓝牙:
- 使用 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- 确认 adapter 不为 null(设备是否支持蓝牙),并检查 adapter.isEnabled() 决定是否提示用户打开蓝牙。
- 获取运行时权限(Android 12 及以上需要 BLUETOOTH_CONNECT 等权限),并在必要时启用位置权限(Android 10 及之前)。
- 检查并打开蓝牙:
-
设备扫描与配对(可选)
- 如果设备未配对,可以通过 startDiscovery() 搜索附近的经典蓝牙设备,也可以跳转到系统蓝牙页面,让用户完成配对。
- 执行 createBond() 方法发起配对(部分设备可能不需要手动调用,系统会自动配对)。
- 成功配对后,可以在系统设置中看到已配对设备,可从 BluetoothAdapter.getBondedDevices() 获取。
-
使用 SPP 连接设备
- 通过已配对设备对象:BluetoothDevice device = …
- 使用 UUID 获取蓝牙串口通道,通常为通用的 SPP UUID(00001101-0000-1000-8000-00805F9B34FB),或设备提供的自定义 UUID。
- 调用 device.createRfcommSocketToServiceRecord(uuid) 获取 BluetoothSocket,对其进行 connect() 操作。
- 连接成功后,获取输入输出流:
- InputStream is = bluetoothSocket.getInputStream();
- OutputStream os = bluetoothSocket.getOutputStream();
-
数据收发与解析
- 通过 InputStream 读取设备返回的数据,根据协议进行解析。
- 通过 OutputStream 向设备发送数据(透传协议通常可直接发送二进制/文本)。
- 注意线程处理:一般应在单独的线程或异步任务中进行收发操作,避免阻塞 UI。
-
断开与资源释放
- 在页面退出或不再需要蓝牙连接时,调用 bluetoothSocket.close() 释放资源。
- 注意处理异常及断线重连逻辑。
三、BLE(低功耗蓝牙)开发流程
-
打开蓝牙与权限检查
- 同样需要检查 BluetoothAdapter 是否可用,并在 AndroidManifest.xml 中声明所需权限,Android 12 及以上需要 BLUETOOTH_SCAN、BLUETOOTH_CONNECT 等;低版本还要精确定位权限。
- 在运行时请求相应权限,确保能够进行 BLE 扫描和连接。
-
设备扫描
- 获取 BluetoothLeScanner scanner = bluetoothAdapter.getBluetoothLeScanner();
- 使用 scanner.startScan(…) 开始扫描,通过回调 onScanResult() 获取附近的 BLE 设备。
- 如果只想连接已知的设备 MAC 地址,也可以通过 bluetoothAdapter.getRemoteDevice(mac) 直接获取 BluetoothDevice 对象,然后发起连接。
-
发起 GATT 连接
- BluetoothDevice device = …
- BluetoothGatt bluetoothGatt = device.connectGatt(context, false, gattCallback);
- context:一般为当前 Activity 或应用上下文
- false 表示不使用自动重连机制(可根据需求设为 true)
- gattCallback:连接和数据通信过程的回调
-
发现服务与特征
- 在 onConnectionStateChange() 中处理连接成功或失败。连接成功后,调用 bluetoothGatt.discoverServices() 发起服务发现。
- 在 onServicesDiscovered() 回调中获取到可用服务: bluetoothGatt.getServices()。
- 根据设备协议或文档,找到对应 Service UUID 和 Characteristic UUID。
-
特征(Characteristic)读写与通知
-
写数据
- 得到目标 characteristic 实例后:
BluetoothGattCharacteristic characteristic = …
characteristic.setValue(需要发送的字节数组);
bluetoothGatt.writeCharacteristic(characteristic); - 在 onCharacteristicWrite() 回调中查看写入结果。
- 得到目标 characteristic 实例后:
-
读数据
- bluetoothGatt.readCharacteristic(characteristic);
- 在 onCharacteristicRead() 回调中处理读取到的值。
-
订阅通知(或指示)
- 先设置 Notification:
bluetoothGatt.setCharacteristicNotification(characteristic, true); - 给描述符(Descriptor)写入开启通知(0x2902 UUID),例如:
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(相应的 UUID);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
bluetoothGatt.writeDescriptor(descriptor); - 当设备有数据主动推送时,会在 onCharacteristicChanged() 回调中接收到实时数据。
- 先设置 Notification:
-
-
数据解析与处理
- 在透传模式下,BLE 通常支持直接发送和接收二进制流。
- 需要根据你与设备约定的协议封包形式进行组包、拆包、校验等操作。
-
断开与资源释放
- 不需要时,调用 bluetoothGatt.close() 断开连接并释放资源。
- 注意在不同回调中正确处理错误、超时和异常情况,并做好重连策略。
四、常见调试方法与注意事项
-
调试工具
- 对于 SPP,可以用安卓的串口调试类 App(或第三方调试器)测试发送/接收;也可以使用桌面端工具与硬件先行验证。
- 对于 BLE,可以使用例如 “nRF Connect” 或 “BLE Scanner” 等 App;它们可以列出设备 GATT 服务、特征,并手动进行读写和订阅。
-
权限与兼容性
- 从 Android 6.0 起,蓝牙扫描需要定位权限;Android 10(29) 开始需要精确定位权限。
- Android 12(31) 之后,新增了 BLUETOOTH_SCAN、BLUETOOTH_CONNECT 等权限,需要区分声明和请求。
- 尽量在运行时,而非仅在 Manifest 中申请权限,保证在实际使用时已经拿到授权。
-
扫描与连接超时策略
- BLE 扫描若持续过久,会消耗电量并触发系统限制,需要合理控制扫描时长。
- 在连接后要有超时或重试机制,以免卡在连接状态或等待回调无人处理。
-
断线与重连
- 无论是 SPP 还是 BLE,移动环境中蓝牙断线较常见,需要在回调中监控连接状态并尝试重连。
- 注意清理资源,避免重复持有 BluetoothSocket 或 BluetoothGatt 对象而不调用 close()。
-
性能与功耗
- BLE 的设计初衷是低功耗,需尽量减少无用的扫描、连接和大数据量的持续传输。
- 对于 SPP,如果需要持续大数据通信,可以关注速度和稳定性(部分设备可能会有带宽和延时限制)。
五、参考链接
-
官方文档
-
第三方工具/库
- nRF Connect (Nordic)
- BLE Scanner
- RxAndroidBle(如果你想用 RxJava 处理 BLE 流程)
总结
- SPP(经典蓝牙)模式下,Android 相对简单,和传统串口思路类似,通过 BluetoothSocket 进行数据收发;但需先进行配对。
- BLE 模式下,需要进行服务与特征的发现、读写、通知订阅等,更灵活但也更复杂;需注意权限、回调处理和断线重连。
- 在 Android 开发中,与 Windows 类似,你需要对硬件和协议充分了解,使用对应的 API 进行数据通讯,并做好异常处理及权限管理。
- 优先用第三方应用或调试工具验证设备与数据链路可行性,然后再在自己项目中实现业务逻辑。
通过上述步骤,就能够在 Android 平台上实现对同时支持 SPP 和 BLE 的蓝牙设备进行透传通信的基本流程。结合之前的 Windows 部分,你可以分别在两个平台上完成配对、连接、数据读写以及后续的设备管理和异常处理。祝开发顺利!