Browse Source

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

master
白凤吉 4 months ago
parent
commit
87bc73ac9f
  1. 27
      app/src/main/java/com/iflytop/profilometer/api/ble/BleApi.java
  2. 5
      app/src/main/java/com/iflytop/profilometer/api/ble/BleRoutes.kt
  3. 82
      app/src/main/java/com/iflytop/profilometer/core/bluetooth/BleManager.java

27
app/src/main/java/com/iflytop/profilometer/api/ble/BleApi.java

@ -1,10 +1,8 @@
package com.iflytop.profilometer.api.ble; package com.iflytop.profilometer.api.ble;
import android.content.Context; import android.content.Context;
import android.os.Build;
import android.util.Log; import android.util.Log;
import com.iflytop.profilometer.ProfilometerApplication;
import com.iflytop.profilometer.common.result.Result; import com.iflytop.profilometer.common.result.Result;
import com.iflytop.profilometer.core.bluetooth.BleManager; import com.iflytop.profilometer.core.bluetooth.BleManager;
@ -47,5 +45,30 @@ public class BleApi {
} }
} }
/**
* 链接蓝牙设备
*/
public String connect(String mac) {
try {
BleManager.getInstance(context).connectToDevice(mac);
return Result.success();
} catch (Exception e) {
Log.e(TAG, "链接蓝牙设备失败", e);
return Result.failed("链接蓝牙设备失败");
}
}
/**
* 断开链接蓝牙设备
*/
public String disconnect() {
try {
BleManager.getInstance(context).disconnect();
return Result.success();
} catch (Exception e) {
Log.e(TAG, "断开蓝牙设备链接失败", e);
return Result.failed("断开蓝牙设备链接失败");
}
}
} }

5
app/src/main/java/com/iflytop/profilometer/api/ble/BleRoutes.kt

@ -31,12 +31,17 @@ fun Routing.bleRoutes(context: Context) {
* *
*/ */
post("/api/ble/connect") { post("/api/ble/connect") {
val params = call.receive<Map<String, String>>()
val jsonResponse = api.connect(params["mac"])
call.respondText(jsonResponse, ContentType.Application.Json)
} }
/** /**
* *
*/ */
post("/api/ble/disconnect") { post("/api/ble/disconnect") {
val jsonResponse = api.disconnect()
call.respondText(jsonResponse, ContentType.Application.Json)
} }
} }

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

@ -26,7 +26,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* BleManager 用于管理蓝牙相关的功能包括权限检查扫描设备和连接设备
* BleManager 用于管理蓝牙相关的功能包括权限检查扫描设备连接和断开设备
* 本类采用单例模式确保整个应用中只有一个实例 * 本类采用单例模式确保整个应用中只有一个实例
*/ */
public class BleManager { public class BleManager {
@ -35,27 +35,21 @@ public class BleManager {
// 单例实例 // 单例实例
private static BleManager instance; private static BleManager instance;
// Android 系统蓝牙管理器
private final BluetoothManager bluetoothManager; private final BluetoothManager bluetoothManager;
// 蓝牙适配器
private BluetoothAdapter bluetoothAdapter; private BluetoothAdapter bluetoothAdapter;
// 蓝牙低功耗扫描器
private BluetoothLeScanner bluetoothLeScanner; private BluetoothLeScanner bluetoothLeScanner;
// 保存扫描到的蓝牙设备列表
private final List<BluetoothDevice> scannedDevices = new ArrayList<>(); private final List<BluetoothDevice> scannedDevices = new ArrayList<>();
// 扫描回调对象
private ScanCallback scanCallback; private ScanCallback scanCallback;
// 蓝牙连接操作返回的 BluetoothGatt 对象
private BluetoothGatt bluetoothGatt; private BluetoothGatt bluetoothGatt;
// 应用上下文使用 ApplicationContext 防止内存泄露
private final Context context; private final Context context;
/** /**
* 私有构造函数防止外部直接实例化 * 私有构造函数防止外部直接实例化
*
* @param context 上下文 * @param context 上下文
*/ */
private BleManager(Context context) { private BleManager(Context context) {
// 使用 ApplicationContext 避免内存泄露
// 使用 ApplicationContext 防止内存泄露
this.context = context.getApplicationContext(); this.context = context.getApplicationContext();
bluetoothManager = (BluetoothManager) this.context.getSystemService(Context.BLUETOOTH_SERVICE); bluetoothManager = (BluetoothManager) this.context.getSystemService(Context.BLUETOOTH_SERVICE);
if (bluetoothManager != null) { if (bluetoothManager != null) {
@ -64,7 +58,8 @@ public class BleManager {
} }
/** /**
* 获取单例实例确保整个应用中只有一个 BleManager 对象
* 获取单例实例确保全局只有一个 BleManager 对象
*
* @param context 上下文 * @param context 上下文
* @return 单例 BleManager 实例 * @return 单例 BleManager 实例
*/ */
@ -77,7 +72,8 @@ public class BleManager {
/** /**
* 辅助方法检查指定权限是否已被授予 * 辅助方法检查指定权限是否已被授予
* @param permission 权限名称例如 Manifest.permission.BLUETOOTH_SCAN
*
* @param permission 权限名称
* @return true 表示已授予false 表示未授予 * @return true 表示已授予false 表示未授予
*/ */
private boolean hasPermission(String permission) { private boolean hasPermission(String permission) {
@ -85,9 +81,8 @@ public class BleManager {
} }
/** /**
* 检查并请求必要的权限例如位置权限BLUETOOTH_SCANBLUETOOTH_CONNECT
* 该方法需要在 Activity 中调用并在 onRequestPermissionsResult 中处理回调
* 需要 API 31Android S及以上版本
* 检查并请求必要权限例如位置BLUETOOTH_SCANBLUETOOTH_CONNECT
* 此方法需要在 Activity 中调用并在 onRequestPermissionsResult 中处理回调
* *
* @param activity 当前 Activity * @param activity 当前 Activity
*/ */
@ -110,7 +105,7 @@ public class BleManager {
/** /**
* 提示用户蓝牙未开启 * 提示用户蓝牙未开启
* 注意此方法不自动开启蓝牙而是直接通过 Toast 提示用户蓝牙未开启请先开启蓝牙
* 如果蓝牙未开启直接通过 Toast 提示用户蓝牙未开启请先开启蓝牙
* *
* @param activity 当前 Activity * @param activity 当前 Activity
*/ */
@ -122,13 +117,15 @@ public class BleManager {
if (bluetoothAdapter.isEnabled()) { if (bluetoothAdapter.isEnabled()) {
return; return;
} }
// 直接提示用户蓝牙未开启无需弹出对话框要求开启
// 提示用户蓝牙未开启
Toast.makeText(activity, "蓝牙未开启,请先开启蓝牙", Toast.LENGTH_LONG).show(); Toast.makeText(activity, "蓝牙未开启,请先开启蓝牙", Toast.LENGTH_LONG).show();
// 可选这里不再调用自动开启逻辑而是等待用户手动开启蓝牙
// startScan() 内部也会检查蓝牙状态
} }
/** /**
* 开始扫描 BLE 设备扫描结果保存到 scannedDevices 列表中
* 需要确保蓝牙已开启且 BLUETOOTH_SCAN 权限已授予
* 开始扫描 BLE 设备扫描结果保存到 scannedDevices 列表中
* 需要确保蓝牙已开启且 BLUETOOTH_SCAN 权限已授予
*/ */
@SuppressLint("MissingPermission") @SuppressLint("MissingPermission")
public void startScan() { public void startScan() {
@ -145,14 +142,12 @@ public class BleManager {
Log.e(TAG, "获取 BluetoothLeScanner 失败"); Log.e(TAG, "获取 BluetoothLeScanner 失败");
return; return;
} }
// 清空上一次扫描结果
// 清空上一次扫描结果
scannedDevices.clear(); scannedDevices.clear();
// 定义扫描回调
scanCallback = new ScanCallback() { scanCallback = new ScanCallback() {
@Override @Override
public void onScanResult(int callbackType, ScanResult result) { public void onScanResult(int callbackType, ScanResult result) {
BluetoothDevice device = result.getDevice(); BluetoothDevice device = result.getDevice();
// 添加新设备到列表中避免重复
if (device != null && !scannedDevices.contains(device)) { if (device != null && !scannedDevices.contains(device)) {
scannedDevices.add(device); scannedDevices.add(device);
Log.d(TAG, "发现设备: " + device.getName() + " - " + device.getAddress()); Log.d(TAG, "发现设备: " + device.getName() + " - " + device.getAddress());
@ -175,13 +170,12 @@ public class BleManager {
Log.e(TAG, "BLE 扫描失败,错误码:" + errorCode); Log.e(TAG, "BLE 扫描失败,错误码:" + errorCode);
} }
}; };
// 开始扫描
bluetoothLeScanner.startScan(scanCallback); bluetoothLeScanner.startScan(scanCallback);
} }
/** /**
* 停止 BLE 设备扫描 * 停止 BLE 设备扫描
* 需要确保 BLUETOOTH_SCAN 权限已被授予
* 需要确保蓝牙已开启且具有 BLUETOOTH_SCAN 权限
*/ */
@SuppressLint("MissingPermission") @SuppressLint("MissingPermission")
public void stopScan() { public void stopScan() {
@ -200,19 +194,17 @@ public class BleManager {
/** /**
* 返回当前扫描到的设备列表 * 返回当前扫描到的设备列表
* 直接返回内部保存的 List<BluetoothDevice> 对象
* *
* @return 蓝牙设备列表
* @return List<BluetoothDevice> 扫描到的蓝牙设备列表
*/ */
public List<BluetoothDevice> getScannedDevices() { public List<BluetoothDevice> getScannedDevices() {
return scannedDevices; return scannedDevices;
} }
/** /**
* 判断是否已经有设备建立了蓝牙连接
* 这里通过 BluetoothGatt 是否为 null 进行简单判断
* 判断是否已有设备建立了蓝牙连接简单判断 BluetoothGatt 是否非空
* *
* @return 如果已有设备连接返回 true否则返回 false
* @return true 表示已有设备连接否则返回 false
*/ */
public boolean isConnected() { public boolean isConnected() {
return bluetoothGatt != null; return bluetoothGatt != null;
@ -220,9 +212,10 @@ public class BleManager {
/** /**
* 尝试连接指定的 BLE 设备 * 尝试连接指定的 BLE 设备
* 传入设备的 MAC 地址通过 bluetoothAdapter.getRemoteDevice() 获取 BluetoothDevice 对象再调用 connectGatt 进行连接
* 如果当前已连接的设备和传入的 MAC 地址相同则不做任何操作
* 如果当前已连接其他设备则先断开当前连接再连接新设备
* *
* @param macAddress 设备的 MAC 地址字符串
* @param macAddress 目标设备的 MAC 地址字符串
*/ */
@SuppressLint("MissingPermission") @SuppressLint("MissingPermission")
public void connectToDevice(String macAddress) { public void connectToDevice(String macAddress) {
@ -234,10 +227,22 @@ public class BleManager {
Log.e(TAG, "BLUETOOTH_CONNECT 权限未授予"); Log.e(TAG, "BLUETOOTH_CONNECT 权限未授予");
return; return;
} }
// 如果当前已有设备连接
if (bluetoothGatt != null) {
BluetoothDevice connectedDevice = bluetoothGatt.getDevice();
if (connectedDevice != null && connectedDevice.getAddress().equals(macAddress)) {
// 如果新连接的设备与当前已连接设备相同则不做任何操作
Log.d(TAG, "设备已连接,无需重复连接: " + connectedDevice.getName());
return;
} else {
// 否则断开当前连接
disconnect();
}
}
try { try {
// 根据 MAC 地址获取 BluetoothDevice 对象 // 根据 MAC 地址获取 BluetoothDevice 对象
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(macAddress); BluetoothDevice device = bluetoothAdapter.getRemoteDevice(macAddress);
// 建立蓝牙连接connectGatt 为异步操作
// 建立蓝牙连接异步操作
bluetoothGatt = device.connectGatt(context, false, new BluetoothGattCallback() { bluetoothGatt = device.connectGatt(context, false, new BluetoothGattCallback() {
@Override @Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
@ -253,4 +258,19 @@ public class BleManager {
Log.e(TAG, "无效的 MAC 地址: " + macAddress, e); Log.e(TAG, "无效的 MAC 地址: " + macAddress, e);
} }
} }
/**
* 断开当前已连接的蓝牙设备
* 如果当前有连接的设备则调用 disconnect() close() 方法断开连接
* 并将内部的 bluetoothGatt 置为 null
*/
@SuppressLint("MissingPermission")
public void disconnect() {
if (bluetoothGatt != null) {
bluetoothGatt.disconnect();
bluetoothGatt.close();
bluetoothGatt = null;
Log.d(TAG, "当前蓝牙设备已断开连接");
}
}
} }
Loading…
Cancel
Save