为了优化经典蓝牙(Classic Bluetooth)和低功耗蓝牙(Bluetooth Low Energy, BLE)的操作,我们可以将功能封装到一个工具类中,支持扫描、连接、通信,并兼容高版本 Android 的动态权限申请。以下是完整的工具类实现。
- 工具类功能
经典蓝牙:
扫描设备。
连接设备。
发送和接收数据。
BLE 蓝牙:
扫描设备。
连接设备。
发送和接收数据(通过 GATT 特征值)。
权限管理:
动态申请权限(包括 ACCESS_FINE_LOCATION、BLUETOOTH_SCAN、BLUETOOTH_CONNECT)。
高版本兼容:
支持 Android 12 及以上版本的权限要求。
-
工具类实现
2.1 BluetoothHelper.javaimport android.Manifest;
import android.annotation.SuppressLint;
import android.bluetooth.*;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;public class BluetoothHelper {
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); // SPP UUID private static final int PERMISSION_REQUEST_CODE = 100; private Context context; private BluetoothAdapter bluetoothAdapter; private BluetoothLeScanner bleScanner; private BluetoothSocket bluetoothSocket; private BluetoothGatt bluetoothGatt; private Handler handler; private List<BluetoothDevice> classicDevices = new ArrayList<>(); private List<BluetoothDevice> bleDevices = new ArrayList<>(); // BLE 相关变量 private BluetoothGattCharacteristic writeCharacteristic; private BluetoothGattCharacteristic notifyCharacteristic; // 回调接口 public interface ScanCallback { void onClassicDeviceFound(BluetoothDevice device); void onBleDeviceFound(BluetoothDevice device); void onScanFailed(String error); } public interface ConnectionCallback { void onConnected(); void onConnectionFailed(String error); } public interface DataCallback { void onDataReceived(byte[] data); void onDataSent(boolean success); } public BluetoothHelper(Context context) { this.context = context; this.handler = new Handler(Looper.getMainLooper()); this.bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (bluetoothAdapter != null) { this.bleScanner = bluetoothAdapter.getBluetoothLeScanner(); } } // 检查权限 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 && ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED; } else { return ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED; } } // 请求权限 public void requestPermissions() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { ActivityCompat.requestPermissions((MainActivity) context, new String[]{ Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.ACCESS_FINE_LOCATION }, PERMISSION_REQUEST_CODE); } else { ActivityCompat.requestPermissions((MainActivity) context, new String[]{ Manifest.permission.ACCESS_FINE_LOCATION }, PERMISSION_REQUEST_CODE); } } // 开始扫描经典蓝牙设备 public void startClassicScan(ScanCallback callback) { if (!checkPermissions()) { callback.onScanFailed("Permissions not granted"); return; } classicDevices.clear(); IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); context.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); classicDevices.add(device); callback.onClassicDeviceFound(device); } } }, filter); bluetoothAdapter.startDiscovery(); } // 开始扫描 BLE 设备 @SuppressLint("MissingPermission") public void startBleScan(ScanCallback callback) { if (!checkPermissions()) { callback.onScanFailed("Permissions not granted"); return; } bleDevices.clear(); bleScanner.startScan(new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { BluetoothDevice device = result.getDevice(); bleDevices.add(device); callback.onBleDeviceFound(device); } @Override public void onScanFailed(int errorCode) { callback.onScanFailed("BLE scan failed with error code: " + errorCode); } }); } // 停止扫描 @SuppressLint("MissingPermission") public void stopScan() { bluetoothAdapter.cancelDiscovery(); if (bleScanner != null) { bleScanner.stopScan(null); } } // 连接经典蓝牙设备 public void connectClassicDevice(BluetoothDevice device, ConnectionCallback callback) { new Thread(() -> { try { bluetoothSocket = device.createRfcommSocketToServiceRecord(MY_UUID); bluetoothSocket.connect(); handler.post(callback::onConnected); } catch (IOException e) { handler.post(() -> callback.onConnectionFailed(e.getMessage())); } }).start(); } // 连接 BLE 设备 @SuppressLint("MissingPermission") public void connectBleDevice(BluetoothDevice device, BluetoothGattCallback gattCallback) { bluetoothGatt = device.connectGatt(context, false, gattCallback); } // 发送数据(经典蓝牙) public void sendClassicData(byte[] data, DataCallback callback) { new Thread(() -> { try { OutputStream outputStream = bluetoothSocket.getOutputStream(); outputStream.write(data); handler.post(() -> callback.onDataSent(true)); } catch (IOException e) { handler.post(() -> callback.onDataSent(false)); } }).start(); } // 接收数据(经典蓝牙) public void receiveClassicData(DataCallback callback) { new Thread(() -> { try { InputStream inputStream = bluetoothSocket.getInputStream(); byte[] buffer = new byte[1024]; int bytes; while ((bytes = inputStream.read(buffer)) != -1) { byte[] receivedData = new byte[bytes]; System.arraycopy(buffer, 0, receivedData, 0, bytes); handler.post(() -> callback.onDataReceived(receivedData)); } } catch (IOException e) { handler.post(() -> callback.onDataReceived(null)); } }).start(); } // 发送数据(BLE) @SuppressLint("MissingPermission") public void sendBleData(byte[] data, DataCallback callback) { if (writeCharacteristic != null && bluetoothGatt != null) { writeCharacteristic.setValue(data); bluetoothGatt.writeCharacteristic(writeCharacteristic); handler.post(() -> callback.onDataSent(true)); } else { handler.post(() -> callback.onDataSent(false)); } } // 启用通知以接收数据(BLE) @SuppressLint("MissingPermission") public void enableBleNotifications(BluetoothGattCharacteristic characteristic, DataCallback callback) { if (bluetoothGatt != null) { bluetoothGatt.setCharacteristicNotification(characteristic, true); BluetoothGattDescriptor descriptor = characteristic.getDescriptor( UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")); if (descriptor != null) { descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); bluetoothGatt.writeDescriptor(descriptor); } } } // 断开连接 public void disconnect() { try { if (bluetoothSocket != null) { bluetoothSocket.close(); } if (bluetoothGatt != null) { bluetoothGatt.disconnect(); bluetoothGatt.close(); } } catch (IOException e) { e.printStackTrace(); } }
}
2.2 使用示例
扫描设备
BluetoothHelper bluetoothHelper = new BluetoothHelper(this);
// 扫描经典蓝牙设备
bluetoothHelper.startClassicScan(new BluetoothHelper.ScanCallback() {
@Override
public void onClassicDeviceFound(BluetoothDevice device) {
Log.d("BluetoothHelper", "Classic Device Found: " + device.getName());
}
@Override
public void onBleDeviceFound(BluetoothDevice device) {
Log.d("BluetoothHelper", "BLE Device Found: " + device.getName());
}
@Override
public void onScanFailed(String error) {
Log.e("BluetoothHelper", "Scan Failed: " + error);
}
});
// 扫描 BLE 设备
bluetoothHelper.startBleScan(new BluetoothHelper.ScanCallback() {
@Override
public void onClassicDeviceFound(BluetoothDevice device) {
Log.d("BluetoothHelper", "Classic Device Found: " + device.getName());
}
@Override
public void onBleDeviceFound(BluetoothDevice device) {
Log.d("BluetoothHelper", "BLE Device Found: " + device.getName());
}
@Override
public void onScanFailed(String error) {
Log.e("BluetoothHelper", "Scan Failed: " + error);
}
});
连接设备
// 连接经典蓝牙设备
bluetoothHelper.connectClassicDevice(device, new BluetoothHelper.ConnectionCallback() {
@Override
public void onConnected() {
Log.d("BluetoothHelper", "Classic Device Connected");
}
@Override
public void onConnectionFailed(String error) {
Log.e("BluetoothHelper", "Connection Failed: " + error);
}
});
// 连接 BLE 设备
bluetoothHelper.connectBleDevice(device, new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.d("BluetoothHelper", "BLE Device Connected");
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.d("BluetoothHelper", "BLE Device Disconnected");
}
}
});
经典蓝牙发送和接收数据
// 发送数据(经典蓝牙)
bluetoothHelper.sendClassicData("Hello Bluetooth".getBytes(), new BluetoothHelper.DataCallback() {
@Override
public void onDataReceived(byte[] data) {
// 处理接收到的数据
}
@Override
public void onDataSent(boolean success) {
Log.d("BluetoothHelper", "Data Sent: " + success);
}
});
// 接收数据(经典蓝牙)
bluetoothHelper.receiveClassicData(new BluetoothHelper.DataCallback() {
@Override
public void onDataReceived(byte[] data) {
Log.d("BluetoothHelper", "Data Received: " + new String(data));
}
@Override
public void onDataSent(boolean success) {
// 无需处理
}
});
BLE蓝牙发送和接收数据
// 连接 BLE 设备
bluetoothHelper.connectBleDevice(device, new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
gatt.discoverServices();
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
BluetoothGattService service = gatt.getService(UUID.fromString("你的服务UUID"));
if (service != null) {
writeCharacteristic = service.getCharacteristic(UUID.fromString("写特征值UUID"));
notifyCharacteristic = service.getCharacteristic(UUID.fromString("通知特征值UUID"));
// 启用通知
bluetoothHelper.enableBleNotifications(notifyCharacteristic, new BluetoothHelper.DataCallback() {
@Override
public void onDataReceived(byte[] data) {
Log.d("BluetoothHelper", "BLE Data Received: " + new String(data));
}
@Override
public void onDataSent(boolean success) {
// 无需处理
}
});
}
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
byte[] data = characteristic.getValue();
Log.d("BluetoothHelper", "BLE Notification Data: " + new String(data));
}
});
// 发送数据(BLE)
bluetoothHelper.sendBleData("Hello BLE".getBytes(), new BluetoothHelper.DataCallback() {
@Override
public void onDataReceived(byte[] data) {
// 无需处理
}
@Override
public void onDataSent(boolean success) {
Log.d("BluetoothHelper", "BLE Data Sent: " + success);
}
});
2.3 注意事项
权限管理:
在 Android 12 及以上版本,需要动态申请 BLUETOOTH_SCAN 和 BLUETOOTH_CONNECT 权限。
在 Android 11 及以下版本,需要动态申请 ACCESS_FINE_LOCATION 权限。
高版本兼容:
使用 @SuppressLint("MissingPermission") 忽略权限检查,确保在实际运行时已授予权限。
线程管理:
经典蓝牙的通信操作应在后台线程中进行,避免阻塞主线程。
通过以上工具类,你可以轻松实现经典蓝牙和 BLE 的扫描、连接和通信功能,并兼容高版本 Android 的权限要求。