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

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.dtcms.com/a/312407.html

相关文章:

  • Redis+Lua的分布式限流器
  • C++编译过程与GDB调试段错误和死锁问题
  • 北邮:LLM强化学习架构Graph-R1
  • C++-二叉树OJ题
  • 【反转字符串中的单词】
  • 从零开始设计一个分布式KV存储:基于Raft的协程化实现
  • 吴恩达【prompt提示词工程】学习笔记
  • C# async await 实现机制详解
  • GR-3:字节跳动推出40亿参数通用机器人大模型,精确操作提升250%,开启具身智能新纪元!
  • FasrCGI
  • ospf笔记和 综合实验册
  • visual studio code 怎样将主题修改成亮色,并且配置中文界面
  • zookeeper常见命令和常见应用
  • MySQL——运维篇
  • K8S部署ELK(五):集成Kibana实现日志可视化
  • MySQL面试题及详细答案 155道(021-040)
  • 使用Database Navigator插件进行连接sqlite报错invalid or incomplete database
  • 2025年开关电源行业深度解析:从传统应用到新兴赛道的黄金赛道
  • MVC 发布
  • 代码随想录day53图论4
  • trace-cmd记录线程被中断打断的时间
  • 笔试——Day27
  • RabbitMQ面试精讲 Day 10:消息追踪与幂等性保证
  • spring-ai-alibaba 之 graph 槽点
  • 【设计模式】4.装饰器模式
  • 2025-0803学习记录21——地表分类产品的精度验证
  • Github怎么只下载某个目录文件?(Git稀疏检出、GitZip for Github插件、在线工具DownGit)Github下载目录
  • linux2.6 和 unix-v6 源码实验
  • Nginx相关实验(2)
  • 【2025/08/03】GitHub 今日热门项目