# 蓝牙BLE模块集成说明 ## 目录结构 ``` capability-ble/src/ └── main/ ├── AndroidManifest.xml # Android 清单文件(权限声明) └── java/ └── com/narutohuo/xindazhou/ble/ ├── api/ # API 接口层 │ └── BLEService.kt # 蓝牙服务接口定义 ├── factory/ # 工厂类层 │ └── BLEServiceFactory.kt # 服务工厂(统一入口) ├── impl/ # 实现层 │ └── BLEServiceImpl.kt # 蓝牙服务具体实现(单例模式) ├── callback/ # 回调接口层 │ └── BLECallback.kt # 蓝牙回调接口(包含 ConnectCallback、HandshakeCallback、CommandCallback、DataCallback) ├── config/ # 配置层 │ └── BLEConstants.kt # 蓝牙常量定义(用户类型、功能码、UUID等) ├── model/ # 数据模型层 │ ├── BLEDevice.kt # BLE设备模型 │ ├── BLECommand.kt # BLE指令模型(包含 AppControlInstruction、SystemControlInstruction) │ ├── BLEResponse.kt # BLE响应模型 │ └── Command.kt # 指令协议数据类 └── util/ # 工具类层 ├── BleScanner.kt # BLE扫描工具 ├── BleConnector.kt # BLE连接工具 ├── BLECrypto.kt # 加密解密工具(AES) ├── BLEPacketBuilder.kt # 协议包构建工具 ├── BLEPacketParser.kt # 协议包解析工具 ├── BLEPacketSplitter.kt # 协议包分包工具 └── BlePacketSender.kt # 协议包发送工具 ``` ## 功能说明 ### 1. api/ 层 - 接口定义 - **职责**:定义蓝牙服务的公共接口,业务层只依赖接口 - **内容**:`BLEService` 接口 - **基础连接功能**: - `startScan()` - 开始扫描BLE设备 - `stopScan()` - 停止扫描 - `connect()` - 连接设备(自动完成握手) - `disconnect()` - 断开连接 - `isConnected()` - 检查连接状态 - **协议封装功能**: - `sendCommand()` - 发送自定义指令 - `sendAppControlCommand()` - 发送应用控制指令 - `sendSystemControlCommand()` - 发送系统控制指令 - `queryVehicleInfo()` - 查询车辆信息 - **便捷方法**: - `setDefense()`, `powerOn()`, `powerOff()`, `findCar()` - `unlockSeat()`, `unlockHandlebar()`, `lockHandlebar()` - `unlockTrunk()`, `lockTrunk()` - `setSensorUnlock()`, `setAmbientLight()`, `setAmbientLightColor()` - `setAutoPowerOffTime()`, `setSpeakerVolume()` - **数据接收监听**: - `setDataReceivedListener()` - 设置数据接收监听器 ### 2. factory/ 层 - 工厂类 - **职责**:提供统一的服务实例获取方式 - **内容**:`BLEServiceFactory` 对象(单例) - **作用**: - 隐藏实现细节,统一入口 - 提供 `create(context)` 方法获取服务实例 ### 3. impl/ 层 - 具体实现 - **职责**:实现 `BLEService` 接口的具体逻辑 - **内容**:`BLEServiceImpl` 单例实现类 - **功能**: - 封装 Android BLE SDK 调用 - 封装 GATT 连接管理 - 封装握手认证(连接时自动完成) - 封装数据分包和组包 - 封装 AES 加密/解密 - 封装协议包构建和解析 ### 4. model/ 层 - 数据模型 - **职责**:定义蓝牙相关的数据模型 - **内容**: - `BLEDevice` - BLE设备模型 - `BLECommand` - BLE指令模型 - `BLEResponse` - BLE响应模型 - `Command` - 指令协议数据类 - `AppControlInstruction` - 应用控制指令常量(对象) - `SystemControlInstruction` - 系统控制指令常量(对象) ### 5. callback/ 层 - 回调接口 - **职责**:定义蓝牙相关的回调接口 - **内容**: - `BLECallback.kt` 文件中包含: - `ConnectCallback` - 连接回调接口 - `HandshakeCallback` - 握手指令回调接口 - `CommandCallback` - 指令发送回调接口 - `DataCallback` - 数据接收回调接口 ### 6. config/ 层 - 配置 - **职责**:定义蓝牙相关的常量配置 - **内容**: - `BLEConstants` - 蓝牙常量定义(用户类型、功能码、UUID等) ### 7. util/ 层 - 工具类 - **职责**:提供蓝牙相关的工具方法 - **内容**: - `BleScanner` - BLE扫描工具 - `BleConnector` - BLE连接工具 - `BLECrypto` - 加密解密工具 - `BLEPacketBuilder` - 协议包构建工具 - `BLEPacketParser` - 协议包解析工具 - `BLEPacketSplitter` - 协议包分包工具 - `BlePacketSender` - 协议包发送工具 ## 架构设计 - **接口隔离**:业务层只依赖接口,不依赖实现 - **工厂模式**:统一入口,隐藏创建逻辑 - **单例模式**:`BLEServiceImpl` 使用单例模式,全局共享同一个连接状态 - **完全封装**:所有底层细节(连接、握手、分包、加密等)都在能力层内部完成 ## 使用方式 ### 完整示例(单例模式) ```kotlin import androidx.fragment.app.Fragment import android.widget.Toast import com.narutohuo.xindazhou.ble.factory.BLEServiceFactory import com.narutohuo.xindazhou.ble.api.BLEService import com.narutohuo.xindazhou.ble.config.BLEConstants class VehicleFragment : Fragment() { // 1. 获取单例实例(全局只有一个,在任何地方获取的都是同一个) private val bleService: BLEService = BLEServiceFactory.create(requireContext()) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 2. 连接设备(一键完成扫描+连接+握手) connectDevice() } private fun connectDevice() { // 获取用户信息(实际项目中从用户认证信息中获取) val userId = getUserId() // 16字节 val userType = BLEConstants.USER_TYPE_OWNER // 0x02=车主 bleService.initializeAndConnect( userId = userId, userType = userType, onConnected = { activity?.runOnUiThread { // 连接成功,可以直接使用指令了 Toast.makeText(context, "连接成功", Toast.LENGTH_SHORT).show() } }, onError = { error -> activity?.runOnUiThread { Toast.makeText(context, "连接失败: $error", Toast.LENGTH_SHORT).show() } } ) } // 3. 发送指令(连接成功后调用) private fun lockCar() { // 设防 bleService.setDefense(enabled = true) { response -> activity?.runOnUiThread { if (response.success) { Toast.makeText(context, "设防成功", Toast.LENGTH_SHORT).show() } else { Toast.makeText(context, "设防失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show() } } } } private fun powerOn() { // 上电 bleService.powerOn { response -> activity?.runOnUiThread { if (response.success) { Toast.makeText(context, "上电成功", Toast.LENGTH_SHORT).show() } } } } private fun findCar() { // 寻车 bleService.findCar { response -> activity?.runOnUiThread { if (response.success) { Toast.makeText(context, "寻车成功", Toast.LENGTH_SHORT).show() } } } } private fun getUserId(): ByteArray { // 实际项目中从用户认证信息中获取 return ByteArray(16) { it.toByte() } // 示例数据 } override fun onDestroyView() { super.onDestroyView() // 4. 断开连接(可选,单例会保持连接状态) if (bleService.isConnected()) { bleService.disconnect() } } } ``` ### 步骤说明 1. **获取单例实例**:使用 `BLEServiceFactory.create(context)` 获取服务实例(全局只有一个) 2. **连接设备**:调用 `initializeAndConnect()` 连接设备(自动完成扫描+连接+握手) 3. **发送指令**:连接成功后,调用各种指令方法(如 `setDefense()`、`powerOn()`、`findCar()` 等) 4. **断开连接**:在 `onDestroyView()` 中断开连接(可选) ### 重要说明 1. **单例模式**:`BLEService` 是单例,全局只有一个实例,在任何地方获取的都是同一个 2. **连接状态共享**:所有使用该服务的地方共享同一个连接状态 3. **第一次需要 Context**:第一次获取单例时需要传入 Context,后续获取可以不带(但建议统一使用工厂类) 4. **连接是必须的**:蓝牙不是自动连接的,需要手动调用 `initializeAndConnect()` 连接设备 ### 两种连接方式的区别 #### 方式一:一键连接(推荐,最简单) 使用 `initializeAndConnect()` - **自动完成所有步骤**: - ✅ 自动扫描设备 - ✅ 自动找到设备后连接 - ✅ 自动完成握手和配对 - ✅ 一个方法搞定,无需手动控制 **适用场景**:大多数情况,直接连接即可 ```kotlin // 一键完成:扫描 + 连接 + 握手 bleService.initializeAndConnect( userId = userId, userType = userType, onConnected = { // 连接成功,可以直接使用指令了 }, onError = { error -> // 连接失败 } ) ``` #### 方式二:手动控制(需要选择设备时使用) 使用 `startScan()` + `connect()` - **手动控制每个步骤**: - 1️⃣ 手动开始扫描 - 2️⃣ 手动选择要连接的设备(可以显示设备列表让用户选择) - 3️⃣ 手动停止扫描 - 4️⃣ 手动连接选中的设备 **适用场景**:需要显示设备列表让用户选择,或者需要控制扫描过程 ```kotlin // 1. 开始扫描 bleService.startScan { device: BLEDevice -> // 找到设备,可以显示在列表中让用户选择 println("找到设备: ${device.name}, 地址: ${device.address}") // 可以添加到设备列表,让用户选择 } // 2. 停止扫描(用户选择设备后) bleService.stopScan() // 3. 连接用户选择的设备 val userId = getUserId() // 16字节 val userType = BLEConstants.USER_TYPE_OWNER val selectedDevice = BLEDevice(name = "用户选择的设备", address = "MAC地址", rssi = 0) bleService.connect(selectedDevice, userId, userType) { response -> if (response.success) { // 连接成功,已自动完成握手 } else { // 连接失败 } } ``` **总结**: - **一键连接**:最简单,自动完成所有步骤,推荐使用 - **手动控制**:需要用户选择设备时使用,可以显示设备列表 ## API 参考 ### 基础连接功能 #### `startScan(callback: (BLEDevice) -> Unit)` 开始扫描 BLE 设备 #### `stopScan()` 停止扫描设备 #### `connect(device: BLEDevice, userId: ByteArray, userType: Byte, callback: (BLEResponse) -> Unit)` 连接设备(自动完成握手和配对) #### `disconnect()` 断开连接 #### `isConnected(): Boolean` 检查是否已连接 ### 高级连接功能(推荐使用) #### `initializeAndConnect()` 一键完成扫描+连接+握手(最简单的方式) ```kotlin fun initializeAndConnect( userId: ByteArray, userType: Byte, onConnected: () -> Unit, onDisconnected: (() -> Unit)? = null, onDataReceived: ((ByteArray) -> Unit)? = null, onError: ((String) -> Unit)? = null, scanTimeoutMs: Long = 10000 ) ``` **参数说明**: - `userId`: 用户ID(16字节),用于握手认证 - `userType`: 用户类型(0x01=最高权限, 0x02=车主, 0x03=分享用户) - `onConnected`: 连接成功回调(已自动完成握手和配对) - `onDisconnected`: 断开连接回调(可选) - `onDataReceived`: 数据接收回调(可选) - `onError`: 错误回调(可选) - `scanTimeoutMs`: 扫描超时时间(毫秒),默认10秒 #### `scanAndConnect()` 扫描并连接设备(一键完成扫描+连接) ```kotlin fun scanAndConnect( userId: ByteArray, userType: Byte, scanTimeoutMs: Long = 10000, onScanning: (() -> Unit)? = null, onDeviceFound: ((BLEDevice) -> Unit)? = null, onConnected: () -> Unit, onError: (String) -> Unit ) ``` #### `setConnectionListener()` 设置连接状态监听器(连接/断开时自动回调) ```kotlin fun setConnectionListener( onConnected: () -> Unit, onDisconnected: () -> Unit, onError: (String) -> Unit ) ``` ### 便捷方法 #### `setDefense(enabled: Boolean, callback: (BLEResponse) -> Unit)` 设防/撤防 #### `powerOn(callback: (BLEResponse) -> Unit)` 上电 #### `powerOff(callback: (BLEResponse) -> Unit)` 下电 #### `findCar(callback: (BLEResponse) -> Unit)` 寻车 #### `unlockSeat(callback: (BLEResponse) -> Unit)` 打开座桶锁 #### `unlockHandlebar(callback: (BLEResponse) -> Unit)` 打开龙头锁 #### `lockHandlebar(callback: (BLEResponse) -> Unit)` 关闭龙头锁 #### `unlockTrunk(callback: (BLEResponse) -> Unit)` 打开尾箱锁 #### `lockTrunk(callback: (BLEResponse) -> Unit)` 关闭尾箱锁 #### `setSensorUnlock(enabled: Boolean, callback: (BLEResponse) -> Unit)` 设置感应解锁开关 #### `setAmbientLight(enabled: Boolean, callback: (BLEResponse) -> Unit)` 设置氛围灯开关 #### `setAmbientLightColor(r: Int, g: Int, b: Int, callback: (BLEResponse) -> Unit)` 设置氛围灯颜色 #### `setAutoPowerOffTime(timeSeconds: Int, callback: (BLEResponse) -> Unit)` 设置自动下电时间 #### `setSpeakerVolume(volume: Int, callback: (BLEResponse) -> Unit)` 设置蓝牙音箱音量 ### 通用方法 #### `sendAppControlCommand(instructionType: Byte, data: ByteArray, callback: (BLEResponse) -> Unit)` 发送应用控制指令 **指令类型**(`AppControlInstruction` 对象): - `AppControlInstruction.SET_DEFENSE` - 设撤防 - `AppControlInstruction.POWER_ON_OFF` - 上下电 - `AppControlInstruction.FIND_CAR` - 寻车 - `AppControlInstruction.SEAT_LOCK` - 座桶锁 - `AppControlInstruction.HANDLEBAR_LOCK` - 龙头锁 - `AppControlInstruction.TRUNK_LOCK` - 尾箱锁 #### `sendSystemControlCommand(instructionType: Byte, data: ByteArray, callback: (BLEResponse) -> Unit)` 发送系统控制指令 **指令类型**(`SystemControlInstruction` 对象): - `SystemControlInstruction.SENSOR_UNLOCK` - 感应解锁开关 - `SystemControlInstruction.AMBIENT_LIGHT` - 氛围灯开关 - `SystemControlInstruction.AMBIENT_LIGHT_COLOR` - 氛围灯颜色 - `SystemControlInstruction.AUTO_POWER_OFF_TIME` - 自动下电时间 - `SystemControlInstruction.SPEAKER_VOLUME` - 蓝牙音箱音量 - 更多指令类型请查看 `SystemControlInstruction` 对象 #### `queryVehicleInfo(callback: (BLEResponse) -> Unit)` 查询车辆信息 #### `sendCommand(command: BLECommand, callback: (BLEResponse) -> Unit)` 发送自定义指令 #### `setDataReceivedListener(listener: DataCallback)` 设置数据接收监听器 ## 常量定义 ### 用户类型 ```kotlin BLEConstants.USER_TYPE_HIGHEST // 0x01 - 最高权限 BLEConstants.USER_TYPE_OWNER // 0x02 - 车主 BLEConstants.USER_TYPE_SHARED // 0x03 - 分享用户 ``` ### 功能码 ```kotlin BLEConstants.FUNCTION_CODE_HANDSHAKE // 0x01 - 握手 BLEConstants.FUNCTION_CODE_APP_CONTROL // 0x02 - 应用控制 BLEConstants.FUNCTION_CODE_SYSTEM_CONTROL // 0x03 - 系统控制 BLEConstants.FUNCTION_CODE_SYSTEM_QUERY // 0x04 - 系统查询 BLEConstants.FUNCTION_CODE_SYSTEM_SETTING // 0x05 - 系统设置 ``` ## 注意事项 1. **单例模式**:`BLEServiceImpl` 使用单例模式,全局共享同一个连接状态 2. **自动握手**:`connect()` 方法内部自动完成握手,无需单独调用握手方法 3. **线程安全**:BLE 回调可能在非主线程执行,需要在回调中使用 `activity?.runOnUiThread {}` 切换到主线程更新 UI 4. **错误处理**:所有 API 都通过 `BLEResponse` 返回结果,需要检查 `response.success` 判断是否成功 5. **生命周期管理**:建议在 `onDestroyView()` (Fragment) 或 `onDestroy()` (Activity) 中调用 `disconnect()` 断开连接 6. **获取服务实例**:推荐使用 `BLEServiceFactory.create(context)` 获取服务实例(工厂方法内部使用单例模式) 7. **Fragment 中使用**:在 Fragment 中使用时,使用 `requireContext()` 获取 Context,回调中使用 `activity?.runOnUiThread {}` 更新 UI