当前位置: 首页 > backend >正文

Android 之 蓝牙通信(4.0 BLE)

一、BLE SDK核心实现

1. 权限配置(AndroidManifest.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-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
2. BLE管理器类(BleManager.java)
public class BleManager {private BluetoothAdapter bluetoothAdapter;private BluetoothGatt bluetoothGatt;private Context context;private BleCallback callback;// 回调接口public interface BleCallback {void onDeviceFound(BluetoothDevice device);void onConnected();void onDisconnected();void onDataReceived(byte[] data);void onError(String errorMsg);}public BleManager(Context context, BleCallback callback) {this.context = context;this.callback = callback;bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();}// 检查权限(兼容Android 12+)public boolean checkPermissions() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {return ContextCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_SCAN) == PackageManager.PERMISSION_GRANTED&& ContextCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED;} else {return ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;}}// 扫描设备@SuppressLint("MissingPermission")public void startScan() {if (!checkPermissions()) {callback.onError("Permissions denied");return;}bluetoothAdapter.getBluetoothLeScanner().startScan(scanCallback);}private ScanCallback scanCallback = new ScanCallback() {@Overridepublic void onScanResult(int callbackType, ScanResult result) {callback.onDeviceFound(result.getDevice());}};// 连接设备@SuppressLint("MissingPermission")public void connectDevice(BluetoothDevice device) {bluetoothGatt = device.connectGatt(context, false, gattCallback);}// GATT回调private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {@Overridepublic void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {if (newState == BluetoothProfile.STATE_CONNECTED) {gatt.discoverServices(); // 发现服务callback.onConnected();} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {callback.onDisconnected();}}@Overridepublic void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {callback.onDataReceived(characteristic.getValue()); // 接收数据}};// 写入数据(需指定特征UUID)@SuppressLint("MissingPermission")public void writeData(UUID serviceUuid, UUID charUuid, byte[] data) {BluetoothGattService service = bluetoothGatt.getService(serviceUuid);if (service != null) {BluetoothGattCharacteristic characteristic = service.getCharacteristic(charUuid);if (characteristic != null) {characteristic.setValue(data);bluetoothGatt.writeCharacteristic(characteristic);}}}// 断开连接public void disconnect() {if (bluetoothGatt != null) {bluetoothGatt.disconnect();bluetoothGatt.close();}}
}

二、调用示例(Activity层)

1. 设备扫描页面(DeviceScanActivity.java)
public class DeviceScanActivity extends AppCompatActivity implements BleManager.BleCallback {private BleManager bleManager;private ArrayAdapter<String> deviceAdapter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_scan);ListView deviceList = findViewById(R.id.device_list);deviceAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1);deviceList.setAdapter(deviceAdapter);bleManager = new BleManager(this, this);deviceList.setOnItemClickListener((parent, view, position, id) -> {BluetoothDevice device = (BluetoothDevice) parent.getItemAtPosition(position);bleManager.connectDevice(device); // 点击连接设备});}@Overrideprotected void onResume() {super.onResume();if (bleManager.checkPermissions()) {bleManager.startScan();} else {requestPermissions(); // 动态申请权限}}// 实现回调方法@Overridepublic void onDeviceFound(BluetoothDevice device) {runOnUiThread(() -> deviceAdapter.add(device.getName() + "\n" + device.getAddress()));}@Overridepublic void onConnected() {startActivity(new Intent(this, DeviceControlActivity.class)); // 跳转到控制页}@Overridepublic void onDataReceived(byte[] data) {Log.d("BLE", "Received: " + Arrays.toString(data));}@Overridepublic void onError(String errorMsg) {Toast.makeText(this, errorMsg, Toast.LENGTH_SHORT).show();}
}
2. 设备控制页面(DeviceControlActivity.java)
public class DeviceControlActivity extends AppCompatActivity {private BleManager bleManager;private final UUID SERVICE_UUID = UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb");private final UUID CHAR_UUID = UUID.fromString("0000ffe1-0000-1000-8000-00805f9b34fb");@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_control);bleManager = new BleManager(this, new SimpleCallback());Button btnSend = findViewById(R.id.btn_send);btnSend.setOnClickListener(v -> {byte[] data = {0x01, 0x02, 0x03}; // 示例指令bleManager.writeData(SERVICE_UUID, CHAR_UUID, data);});}// 简化回调(仅处理必要事件)private static class SimpleCallback implements BleManager.BleCallback {@Override public void onDeviceFound(BluetoothDevice device) {}@Override public void onConnected() {}@Override public void onDisconnected() {}@Override public void onDataReceived(byte[] data) {Log.d("BLE", "Data received: " + new String(data));}@Override public void onError(String errorMsg) {}}@Overrideprotected void onDestroy() {bleManager.disconnect(); // 释放资源super.onDestroy();}
}

三.​​BLE传输限制与分包原因​

  1. ​MTU限制​

    • ​默认限制​​:BLE协议有效载荷(Payload)默认20字节(MTU=23,其中3字节为协议头)。
    • ​可协商提升​​:通过MTU协商,Android/iOS设备最高可支持512字节(有效载荷517字节),但实际值受设备硬件和协议栈限制。
  2. ​分包必要性​
    当数据超过MTU时,需手动拆分数据包,避免传输失败或数据截断

四.​​BLE传输数据分包发送

http://www.xdnf.cn/news/16915.html

相关文章:

  • CASAtomic 原子操作详解
  • 1.内核模块
  • 攻防世界-web-csaw-mfw
  • IO流-字节流-FileOutputStream
  • 复现YOLOV5+训练指定数据集
  • 关于Web前端安全防御之安全头配置
  • 最新Android Studio汉化教程--兼容插件包
  • Java Stream API 编程实战
  • MySQL 事务原理 + ACID笔记
  • 【C语言】结构体详解
  • 无人机集群协同三维路径规划,采用冠豪猪优化器(Crested Porcupine Optimizer, CPO)实现,Matlab代码
  • Jetpack Compose for XR:构建下一代空间UI的完整指南
  • C++引用:高效安全的别名机制详解
  • 途游Android面试题及参考答案
  • pytorch 安装
  • 机器翻译的分类:规则式、统计式、神经式MT的核心区别
  • 计算用户日活:从数据设计到可视化的全流程(高频场景题)
  • 深入掌握 ExcelJS:Node.js 中强大的 Excel 操作库
  • RAG 知识库实战指南:基于 Spring AI 构建 AI 知识问答应用
  • GaussDB case when的用法
  • 在win上安装最新的X-anylabeling以及sam2来帮助进行全自动追踪标注
  • 多模态后训练反常识:长思维链SFT和RL的协同困境
  • Git 常用命令指南:从入门到高效开发
  • 【Qt】QObject::startTimer: Timers cannot be started from another thread
  • 考研复习-计算机组成原理-第二章-数据的表示和运算
  • Kazam产生.movie.mux后恢复视频为.mp4
  • 第三章-提示词-高级:开启智能交互新境界(13/36)
  • Steam饥荒联机版多人服务器搭建全解析 -- 阿里云Linux系统构建云服务器
  • MPLS LSP
  • Mysql深入学习:慢sql执行