Browse Source

1.手机蓝牙关闭后,重新开启,唤醒不了。

2.手机系统重启后,没有重启(权限没有了)。加入权限后,服务起来了,但是不进入扫描连接。
3.后台服务在开发者模式下可以被手机关闭。关闭后,服务启动会报错。
4.后台服务ble扫描没有做连接判断。一直在后台扫描导致高耗电。
newdev_shunjiawei
fdp 1 year ago
parent
commit
789a4d3f5d
  1. 15
      local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/BleMediaService.kt
  2. 89
      local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleCompanionManager.kt
  3. 15
      local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt
  4. 2
      local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleServicePlugin.kt
  5. 55
      local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleWakeReceiver.kt

15
local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/BleMediaService.kt

@ -21,6 +21,7 @@ import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.Dispatchers
import com.yunqiinnovation.ble_service.BleConst
import com.yunqiinnovation.ble_service.BleService
import com.yunqiinnovation.ble_service.BleCompanionManager
// 添加蓝牙相关导入
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
@ -95,7 +96,11 @@ class BleMediaService : Service(), CoroutineScope {
private var isBluetoothReceiverRegistered = false
// 添加定期检查蓝牙状态的协程作业
private var bluetoothCheckJob: kotlinx.coroutines.Job? = null
/**
* BLE伴侣设备管理器
* 用于管理设备配对和后台扫描
*/
private var companionManager: BleCompanionManager? = null
/**
* 蓝牙设备连接状态广播接收器
* 监听蓝牙设备的连接和断开事件
@ -169,6 +174,7 @@ class BleMediaService : Service(), CoroutineScope {
when (state) {
BluetoothAdapter.STATE_OFF -> {
Log.w(TAG, "蓝牙已关闭")
//companionManager?.unregisterBackgroundScan()
// 蓝牙关闭时,注销设备连接监听器(保留状态监听器)
unregisterDeviceConnectionReceiver()
}
@ -254,6 +260,9 @@ class BleMediaService : Service(), CoroutineScope {
if (deviceName.equals(TARGET_DEVICE_NAME, ignoreCase = true)) {
Log.i(TAG, "发现已绑定的目标设备: $deviceName")
val pairedUuid = companionManager?.getPairedUuid()
val pairedMac = companionManager?.getPairedMacAddress()
companionManager?.registerBackgroundScan(pairedMac, pairedUuid)
// 注意:这里只能检查绑定状态,无法直接判断连接状态
// 实际连接状态需要通过广播接收器监听
}
@ -390,13 +399,15 @@ class BleMediaService : Service(), CoroutineScope {
// 设置服务状态
isRunning.set(true)
startForeground(NOTIFICATION_ID, createNotification())
// 初始化BLE伴侣设备管理器 - 使用单例模式获取实例
companionManager = BleCompanionManager.getInstance(this)
// 初始化蓝牙监听器
initializeBluetoothListener()
// 启动定期蓝牙状态检查
startBluetoothStatusCheck()
Log.i(TAG, "BLE代理服务已启动")
}

89
local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleCompanionManager.kt

@ -22,10 +22,12 @@ import java.util.UUID
import java.util.regex.Pattern
/**
* BleCompanionManager
* BleCompanionManager - 单例模式
* 用于管理BLE设备的配对和关联
*
* 使用单例模式确保全局只有一个实例,避免重复初始化和资源浪费
*/
class BleCompanionManager(private val context: Context) {
class BleCompanionManager private constructor(private val context: Context) {
private val TAG = "BleCompanionManager"
// 常量定义
@ -35,6 +37,43 @@ class BleCompanionManager(private val context: Context) {
private const val KEY_ASSOCIATION_IDS = "association_ids"
private const val KEY_PAIRED_MAC = "paired_mac"
private const val KEY_PAIRED_UUID = "paired_uuid"
// 单例实例
@Volatile
private var INSTANCE: BleCompanionManager? = null
/**
* 获取BleCompanionManager单例实例
* 使用双重检查锁定模式确保线程安全
*
* @param context 应用上下文,建议使用ApplicationContext
* @return BleCompanionManager实例
*/
fun getInstance(context: Context): BleCompanionManager {
return INSTANCE ?: synchronized(this) {
INSTANCE ?: BleCompanionManager(context.applicationContext).also { INSTANCE = it }
}
}
/**
* 获取已初始化的实例(如果存在)
*
* @return BleCompanionManager实例,如果未初始化则返回null
*/
fun getInstanceIfInitialized(): BleCompanionManager? {
return INSTANCE
}
/**
* 销毁单例实例
* 主要用于测试或特殊情况下的清理
*/
fun destroyInstance() {
synchronized(this) {
INSTANCE?.cleanup()
INSTANCE = null
}
}
}
// 会话保存
@ -44,21 +83,37 @@ class BleCompanionManager(private val context: Context) {
// 用于验证的临时MAC地址
private var pendingMacAddress: String? = null
// 创建PendingIntent
// 创建PendingIntent
val scanIntent = Intent(BleConst.ACTION_SCAN_RESULT)
.setClass(context, BleWakeReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(
context,
0,
scanIntent,
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
} else {
PendingIntent.FLAG_UPDATE_CURRENT
}
)
// 创建PendingIntent
private val pendingIntent by lazy {
val scanIntent = Intent(BleConst.ACTION_SCAN_RESULT)
.setClass(context, BleWakeReceiver::class.java)
PendingIntent.getBroadcast(
context,
0,
scanIntent,
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
} else {
PendingIntent.FLAG_UPDATE_CURRENT
}
)
}
/**
* 清理资源
* 在销毁实例时调用
*/
private fun cleanup() {
try {
unregisterBackgroundScan()
pendingMacAddress = null
} catch (e: Exception) {
Log.e(TAG, "清理资源时发生错误: ${e.message}", e)
}
}
/**
* 获取CompanionDeviceManager服务(使用Activity上下文)
*/

15
local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt

@ -138,7 +138,7 @@ object BleService {
/** 指令发送器实例 */
private val commandSender = BleCommandSender()
private var companionManager: BleCompanionManager? = null
/**
* 检查是否有蓝牙扫描权限
* Android 12+ 需要BLUETOOTH_SCAN权限,之前版本需要ACCESS_FINE_LOCATION权限
@ -597,16 +597,18 @@ object BleService {
// ======================================================================================================
/**
* 自动连接已配对的BLE设备
*
* 该方法会尝试连接之前通过CompanionDeviceManager配对的设备
* 如果没有找到已配对的MAC地址,将不会进行连接
*/
fun connect() {
try {
Log.i(TAG, "设备连接与通信: 自动连接已配对的BLE设备")
// 创建 BleCompanionManager 实例
val companionManager = BleCompanionManager(context)
// 获取 BleCompanionManager 单例实例
companionManager = BleCompanionManager.getInstance(context)
// 获取已配对的 MAC 地址
val pairedMac = companionManager.getPairedMacAddress()
val pairedMac = companionManager?.getPairedMacAddress()
if (pairedMac.isNullOrEmpty()) {
Log.w(TAG, "未找到已配对的设备 MAC 地址")
@ -728,6 +730,7 @@ object BleService {
status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED -> {
updateConnectionState(BleConst.STATE_CONNECTED)
Log.d(TAG, "成功连接Ble蓝牙设备:${g.device.name}")
companionManager?.unregisterBackgroundScan()
// 设置PHY值为2M以提高传输速度
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
try {
@ -761,7 +764,11 @@ object BleService {
newState == BluetoothProfile.STATE_DISCONNECTED -> {
updateConnectionState(BleConst.STATE_DISCONNECTED)
Log.d(TAG, "监听到已断开连接")
disconnectGatt()
val pairedUuid = companionManager?.getPairedUuid()
val pairedMac = companionManager?.getPairedMacAddress()
companionManager?.registerBackgroundScan(pairedMac, pairedUuid)
}
else -> {

2
local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleServicePlugin.kt

@ -68,7 +68,7 @@ class BleServicePlugin : FlutterPlugin, MethodCallHandler, ActivityAware,
BleService.addCallback(this)
// 初始化CompanionManager
bleCompanionManager = BleCompanionManager(context)
bleCompanionManager = BleCompanionManager.getInstance(context)
}
// 设置事件通道 - 简化版

55
local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleWakeReceiver.kt

@ -37,9 +37,13 @@ class BleWakeReceiver : BroadcastReceiver() {
}
}
/**
* 启动BLE服务的改进方法
* 处理Android系统对后台服务启动的限制
*/
private fun startBleService(context: Context) {
try {
// 检查是否存在BleMediaService类,如果不存在则使用BleService
// 检查是否存在BleMediaService类
val serviceClass = try {
Log.d(TAG, "startBleService存在")
Class.forName("com.yunqiinnovation.agent_service.BleMediaService")
@ -48,22 +52,55 @@ class BleWakeReceiver : BroadcastReceiver() {
return
}
// 创建服务Intent,并携带MAC地址
// 创建服务Intent
val serviceIntent = Intent().apply {
setClassName(context, serviceClass.name)
action = BleConst.ACTION_SCAN_RESULT
}
// 启动前台服务
// 启动服务的改进策略
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(serviceIntent)
Log.i(TAG, "已启动前台服务: ${serviceClass.name}")
try {
// 首先尝试启动前台服务
Log.i(TAG, "尝试启动前台服务: ${serviceClass.name}")
context.startForegroundService(serviceIntent)
Log.i(TAG, "前台服务启动成功")
} catch (e: IllegalStateException) {
Log.w(TAG, "前台服务启动失败,尝试其他方式: ${e.message}")
// 如果前台服务启动失败,尝试通过Activity启动
try {
Log.i(TAG, "通过Activity启动服务成功: ${serviceClass.name}")
val activityIntent = context.packageManager.getLaunchIntentForPackage(context.packageName)?.apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
putExtra("auto_start_ble_service", true)
putExtra("ble_service_action", BleConst.ACTION_SCAN_RESULT)
}
if (activityIntent != null) {
context.startActivity(activityIntent)
Log.i(TAG, "通过Activity启动应用,将在前台启动服务")
} else {
Log.e(TAG, "无法获取应用启动Intent")
}
} catch (activityException: Exception) {
Log.e(TAG, "通过Activity启动也失败: ${activityException.message}")
}
} catch (e: Exception) {
Log.e(TAG, "启动前台服务时发生未知错误: ${e.message}", e)
}
} else {
context.startService(serviceIntent)
Log.i(TAG, "已启动服务: ${serviceClass.name}")
// Android 8.0以下直接启动服务
try {
context.startService(serviceIntent)
Log.i(TAG, "已启动服务: ${serviceClass.name}")
} catch (e: Exception) {
Log.e(TAG, "启动服务失败: ${e.message}", e)
}
}
} catch (e: Exception) {
Log.e(TAG, "启动BLE服务失败: ${e.message}", e)
}
}
}
}
Loading…
Cancel
Save