BleScanner.kt 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. package com.narutohuo.xindazhou.ble.util
  2. import android.bluetooth.BluetoothAdapter
  3. import android.bluetooth.BluetoothDevice
  4. import android.bluetooth.BluetoothManager
  5. import android.bluetooth.le.BluetoothLeScanner
  6. import android.bluetooth.le.ScanCallback
  7. import android.bluetooth.le.ScanFilter
  8. import android.bluetooth.le.ScanResult
  9. import android.bluetooth.le.ScanSettings
  10. import android.content.Context
  11. import android.os.Handler
  12. import android.os.Looper
  13. import com.narutohuo.xindazhou.core.log.ILog
  14. /**
  15. * BLE扫描器
  16. *
  17. * 负责 BLE 设备的扫描,返回符合过滤条件的 BluetoothDevice 列表
  18. * 使用 Android 12+ 推荐的 BluetoothLeScanner API
  19. */
  20. class BleScanner(
  21. private val context: Context,
  22. private val onDeviceFound: (BluetoothDevice) -> Unit,
  23. private val onScanFinished: () -> Unit
  24. ) {
  25. private val tag = "BleScanner"
  26. private val bluetoothAdapter: BluetoothAdapter by lazy {
  27. val manager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
  28. manager.adapter
  29. }
  30. private var scanner: BluetoothLeScanner? = null
  31. private var scanning = false
  32. private val scanCallback = object : ScanCallback() {
  33. override fun onScanResult(callbackType: Int, result: ScanResult) {
  34. result.device?.let {
  35. onDeviceFound(it)
  36. stopScan()
  37. }
  38. }
  39. override fun onBatchScanResults(results: List<ScanResult>) {
  40. results.forEach {
  41. it.device?.let { device ->
  42. onDeviceFound(device)
  43. stopScan()
  44. }
  45. }
  46. }
  47. override fun onScanFailed(errorCode: Int) {
  48. ILog.e(tag, "BLE scan failed, error=$errorCode")
  49. stopScan()
  50. }
  51. }
  52. /**
  53. * 开始扫描(默认 10 秒后自动停止)
  54. */
  55. @android.annotation.SuppressLint("MissingPermission")
  56. fun startScan(filterNamePrefix: String? = null, timeoutMs: Long = 10_000L) {
  57. if (scanning) return
  58. scanner = bluetoothAdapter.bluetoothLeScanner
  59. val settings = ScanSettings.Builder()
  60. .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
  61. .build()
  62. val filters = mutableListOf<ScanFilter>()
  63. filterNamePrefix?.let {
  64. filters.add(ScanFilter.Builder().setDeviceName(it).build())
  65. }
  66. try {
  67. scanner?.startScan(filters, settings, scanCallback)
  68. scanning = true
  69. ILog.d(tag, "开始扫描BLE设备,过滤前缀: $filterNamePrefix")
  70. // 超时自动停止
  71. Handler(Looper.getMainLooper()).postDelayed({ stopScan() }, timeoutMs)
  72. } catch (e: SecurityException) {
  73. ILog.e(tag, "扫描权限不足", e)
  74. scanning = false
  75. } catch (e: Exception) {
  76. ILog.e(tag, "启动扫描失败", e)
  77. scanning = false
  78. }
  79. }
  80. /**
  81. * 停止扫描
  82. */
  83. @android.annotation.SuppressLint("MissingPermission")
  84. fun stopScan() {
  85. if (!scanning) return
  86. try {
  87. scanner?.stopScan(scanCallback)
  88. scanning = false
  89. ILog.d(tag, "停止扫描")
  90. onScanFinished()
  91. } catch (e: SecurityException) {
  92. ILog.e(tag, "停止扫描权限不足", e)
  93. } catch (e: Exception) {
  94. ILog.e(tag, "停止扫描失败", e)
  95. }
  96. }
  97. }