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