Android 蓝牙工具类封装:支持经典蓝牙与 BLE,兼容高版本权限

为了优化经典蓝牙(Classic Bluetooth)和低功耗蓝牙(Bluetooth Low Energy, BLE)的操作,我们可以将功能封装到一个工具类中,支持扫描、连接、通信,并兼容高版本 Android 的动态权限申请。以下是完整的工具类实现。

  1. 工具类功能
    经典蓝牙:

扫描设备。

连接设备。

发送和接收数据。

BLE 蓝牙:

扫描设备。

连接设备。

发送和接收数据(通过 GATT 特征值)。

权限管理:

动态申请权限(包括 ACCESS_FINE_LOCATION、BLUETOOTH_SCAN、BLUETOOTH_CONNECT)。

高版本兼容:

支持 Android 12 及以上版本的权限要求。

  1. 工具类实现
    2.1 BluetoothHelper.java

    import 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 的权限要求。

相关推荐
2501_9159184113 分钟前
Fiddler中文版全面评测:功能亮点、使用场景与中文网资源整合指南
android·ios·小程序·https·uni-app·iphone·webview
wen's2 小时前
React Native安卓刘海屏适配终极方案:仅需修改 AndroidManifest.xml!
android·xml·react native
编程乐学3 小时前
网络资源模板--基于Android Studio 实现的聊天App
android·android studio·大作业·移动端开发·安卓移动开发·聊天app
乌云暮年3 小时前
Git简单命令
git·gitee·github·batch命令
没有了遇见5 小时前
Android 通过 SO 库安全存储敏感数据,解决接口劫持问题
android
hsx6665 小时前
使用一个 RecyclerView 构建复杂多类型布局
android
hsx6665 小时前
利用 onMeasure、onLayout、onDraw 创建自定义 View
android
守城小轩5 小时前
Chromium 136 编译指南 - Android 篇:开发工具安装(三)
android·数据库·redis
whysqwhw5 小时前
OkHttp平台抽象机制分析
android
hsx6666 小时前
Android 内存泄漏避坑
android