Browse Source

实现获取蓝牙列表接口,还需完善

master
白凤吉 4 months ago
parent
commit
3cfcb6dc86
  1. 108
      app/src/main/java/com/iflytop/profilometer/core/bluetooth/BleManager.java

108
app/src/main/java/com/iflytop/profilometer/core/bluetooth/BleManager.java

@ -25,21 +25,37 @@ import androidx.core.content.ContextCompat;
import java.util.ArrayList;
import java.util.List;
/**
* BleManager 用于管理蓝牙相关的功能包括权限检查扫描设备和连接设备
* 本类采用单例模式确保整个应用中只有一个实例
*/
public class BleManager {
private static final String TAG = "BLEManager";
// 单例实例
private static BleManager instance;
private BluetoothManager bluetoothManager;
// Android 系统蓝牙管理器
private final BluetoothManager bluetoothManager;
// 蓝牙适配器
private BluetoothAdapter bluetoothAdapter;
// 蓝牙低功耗扫描器
private BluetoothLeScanner bluetoothLeScanner;
private List<BluetoothDevice> scannedDevices = new ArrayList<>();
// 保存扫描到的蓝牙设备列表
private final List<BluetoothDevice> scannedDevices = new ArrayList<>();
// 扫描回调对象
private ScanCallback scanCallback;
// 蓝牙连接操作返回的 BluetoothGatt 对象
private BluetoothGatt bluetoothGatt;
private Context context;
// 应用上下文使用 ApplicationContext 防止内存泄露
private final Context context;
/**
* 私有构造函数防止外部直接实例化
* @param context 上下文
*/
private BleManager(Context context) {
// 使用 ApplicationContext 避免内存泄露
this.context = context.getApplicationContext();
bluetoothManager = (BluetoothManager) this.context.getSystemService(Context.BLUETOOTH_SERVICE);
if (bluetoothManager != null) {
@ -48,7 +64,9 @@ public class BleManager {
}
/**
* 获取单例实例
* 获取单例实例确保整个应用中只有一个 BleManager 对象
* @param context 上下文
* @return 单例 BleManager 实例
*/
public static synchronized BleManager getInstance(Context context) {
if (instance == null) {
@ -58,15 +76,20 @@ public class BleManager {
}
/**
* 辅助方法检查指定权限是否已被授予
* 辅助方法检查指定权限是否已被授予
* @param permission 权限名称例如 Manifest.permission.BLUETOOTH_SCAN
* @return true 表示已授予false 表示未授予
*/
private boolean hasPermission(String permission) {
return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED;
}
/**
* 检查并请求必要权限例如位置BLUETOOTH_SCANBLUETOOTH_CONNECT
* 此方法需要在 Activity 中调用且在 onRequestPermissionsResult 中处理回调
* 检查并请求必要的权限例如位置权限BLUETOOTH_SCANBLUETOOTH_CONNECT
* 该方法需要在 Activity 中调用并在 onRequestPermissionsResult 中处理回调
* 需要 API 31Android S及以上版本
*
* @param activity 当前 Activity
*/
@RequiresApi(api = Build.VERSION_CODES.S)
public void checkAndRequestPermissions(Activity activity) {
@ -85,7 +108,12 @@ public class BleManager {
}
}
/**
* 提示用户蓝牙未开启
* 注意此方法不自动开启蓝牙而是直接通过 Toast 提示用户蓝牙未开启请先开启蓝牙
*
* @param activity 当前 Activity
*/
public void promptAndEnableBluetooth(Activity activity) {
if (bluetoothAdapter == null) {
Log.e(TAG, "该设备不支持蓝牙");
@ -94,13 +122,13 @@ public class BleManager {
if (bluetoothAdapter.isEnabled()) {
return;
}
// 直接提示用户蓝牙未开启无需点击开启
// 直接提示用户蓝牙未开启无需弹出对话框要求开启
Toast.makeText(activity, "蓝牙未开启,请先开启蓝牙", Toast.LENGTH_LONG).show();
startScan();
}
/**
* 开始扫描 BLE 设备扫描结果保存到 scannedDevices 列表中
* 开始扫描 BLE 设备扫描结果将保存到 scannedDevices 列表中
* 需要确保蓝牙已开启且 BLUETOOTH_SCAN 权限已被授予
*/
@SuppressLint("MissingPermission")
public void startScan() {
@ -117,11 +145,14 @@ public class BleManager {
Log.e(TAG, "获取 BluetoothLeScanner 失败");
return;
}
// 清空上一次扫描的结果
scannedDevices.clear();
// 定义扫描回调
scanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
BluetoothDevice device = result.getDevice();
// 添加新设备到列表中避免重复
if (device != null && !scannedDevices.contains(device)) {
scannedDevices.add(device);
Log.d(TAG, "发现设备: " + device.getName() + " - " + device.getAddress());
@ -144,11 +175,13 @@ public class BleManager {
Log.e(TAG, "BLE 扫描失败,错误码:" + errorCode);
}
};
// 开始扫描
bluetoothLeScanner.startScan(scanCallback);
}
/**
* 停止 BLE 设备扫描
* 停止 BLE 设备扫描
* 需要确保 BLUETOOTH_SCAN 权限已被授予
*/
@SuppressLint("MissingPermission")
public void stopScan() {
@ -166,39 +199,58 @@ public class BleManager {
}
/**
* 返回内部扫描到的设备列表直接返回 List<BluetoothDevice>
* 返回当前扫描到的设备列表
* 直接返回内部保存的 List<BluetoothDevice> 对象
*
* @return 蓝牙设备列表
*/
public List<BluetoothDevice> getScannedDevices() {
return scannedDevices;
}
/**
* 判断是否已有蓝牙设备连接简单判断 BluetoothGatt 是否非空
* 判断是否已经有设备建立了蓝牙连接
* 这里通过 BluetoothGatt 是否为 null 进行简单判断
*
* @return 如果已有设备连接返回 true否则返回 false
*/
public boolean isConnected() {
return bluetoothGatt != null;
}
/**
* 尝试连接指定的 BLE 设备
* 尝试连接指定的 BLE 设备
* 传入设备的 MAC 地址通过 bluetoothAdapter.getRemoteDevice() 获取 BluetoothDevice 对象再调用 connectGatt 进行连接
*
* @param macAddress 设备的 MAC 地址字符串
*/
@SuppressLint("MissingPermission")
public void connectToDevice(BluetoothDevice device) {
if (device == null) return;
public void connectToDevice(String macAddress) {
if (macAddress == null || macAddress.isEmpty()) {
Log.e(TAG, "MAC 地址为空");
return;
}
if (!hasPermission(Manifest.permission.BLUETOOTH_CONNECT)) {
Log.e(TAG, "BLUETOOTH_CONNECT 权限未授予");
return;
}
bluetoothGatt = device.connectGatt(context, false, new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.d(TAG, "设备已连接: " + device.getName());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.d(TAG, "设备已断开: " + device.getName());
bluetoothGatt = null;
try {
// 根据 MAC 地址获取 BluetoothDevice 对象
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(macAddress);
// 建立蓝牙连接connectGatt 为异步操作
bluetoothGatt = device.connectGatt(context, false, new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.d(TAG, "设备已连接: " + device.getName());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.d(TAG, "设备已断开: " + device.getName());
bluetoothGatt = null;
}
}
}
});
});
} catch (IllegalArgumentException e) {
Log.e(TAG, "无效的 MAC 地址: " + macAddress, e);
}
}
}
}
Loading…
Cancel
Save