Estimote UWB Android SDK多Beacon连接异常问题咨询
问题分析与解决方案
问题背景
开发Android室内导航应用,采用3个Estimote UWB Beacon及无官方文档的Estimote Android UWB SDK。单Beacon连接时可正常获取位置数据(示例日志:Position of 7B:ED : Distance=0.14999998, Azimuth=null, Elevation=null),但连接第二个Beacon时触发以下错误日志:
- Creating Gms Client session scope
- Error when removing Please check that the ranging is active and theranging profile supports multi-device ranging.
- RangingResultPeerDisconnected address:20:00
不确定问题源于代码、SDK限制,还是Pixel 7 Pro的UWB多设备支持能力。
核心问题排查
1. 代码逻辑缺陷
从提供的代码来看,存在多处影响多设备连接的问题:
- 重复启动/停止扫描:在
startUWBScanning中,两次调用launchUWBConnection时都执行uwbManager.startDeviceScanning,且最后立刻调用uwbManager.stopDeviceScanning,导致扫描流程被中断,无法维持多设备的测距会话。 - 错误的扫描触发时机:每个设备连接时单独启动扫描,不符合UWB扫描的全局逻辑——扫描应仅启动一次,用于发现所有目标Beacon,而非为每个设备重复启动。
- 协程生命周期未绑定:使用
CoroutineScope(Dispatchers.Main.immediate).launch创建无绑定的协程,可能导致内存泄漏,且多设备的rangingResult.collect可能出现冲突。 - 直接使用固定蓝牙地址:未通过扫描发现设备,直接用硬编码地址获取
BluetoothDevice,可能存在设备未处于可连接状态的情况。
2. 设备兼容性确认
Pixel 7 Pro硬件支持UWB,且Google的UWB官方API明确支持多设备测距,因此硬件层面不存在多设备连接限制,问题排除设备硬件因素。
3. SDK潜在限制
错误日志中明确提示ranging profile supports multi-device ranging,说明SDK可能需要配置特定的测距Profile以启用多设备支持。由于SDK无官方文档,需尝试以下方向:
- 检查
EstimoteUWBManager初始化或连接时是否有隐藏的Profile配置参数,用于开启多设备测距。 - 确认SDK是否支持同时连接多个UWB Beacon,部分厂商的UWB SDK可能存在单设备限制。
修正后的代码示例
以下是针对代码问题的优化版本:
class MainActivity : ComponentActivity() { private lateinit var uwbManager: EstimoteUWBManager private val lifecycleScope = LifecycleCoroutineScope(this.lifecycle) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.login) val usernameEditText = findViewById<EditText>(R.id.username) val passwordEditText = findViewById<EditText>(R.id.password) val loginButton = findViewById<Button>(R.id.loginbtn) loginButton.setOnClickListener { lifecycleScope.launch { val username = usernameEditText.text.toString() val password = passwordEditText.text.toString() val encryptedUsername = encryptWithPublicKey(username, publicKeyPEM) val encryptedPassword = encryptWithPublicKey(password, publicKeyPEM) sendSignInCredentialsToLambda(encryptedUsername, encryptedPassword, applicationContext) } } checkPermissionsAndStartUWB() } private fun checkPermissionsAndStartUWB() { val requiredPermissions = arrayOf( Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.UWB_RANGING ) if (requiredPermissions.all { ContextCompat.checkSelfPermission(this, it) == PackageManager.PERMISSION_GRANTED }) { initUWBManager() } else { ActivityCompat.requestPermissions(this, requiredPermissions, 1) } } override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == 1 && grantResults.all { it == PackageManager.PERMISSION_GRANTED }) { initUWBManager() } else { Log.d("PERMISSIONS", "Some permissions are denied") } } private fun initUWBManager() { uwbManager = EstimoteUWBFactory.create() uwbManager.init(this, this) { deniedRequirements -> deniedRequirements.forEach { Log.d("UWBInit", "Requirement denied: $it") } // 初始化完成后启动扫描和多设备连接 startMultiDeviceUWBRanging() } } private fun startMultiDeviceUWBRanging() { val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter() val targetDeviceAddresses = listOf("D8:EB:87:DF:E7:BE", "EC:01:7C:7F:67:50") val targetDevices = targetDeviceAddresses.mapNotNull { address -> bluetoothAdapter?.getRemoteDevice(address) } // 仅启动一次扫描 lifecycleScope.launch { uwbManager.startDeviceScanning(applicationContext) } // 批量连接目标设备 targetDevices.forEach { device -> connectAndRangeDevice(device) } } private fun connectAndRangeDevice(device: BluetoothDevice) { lifecycleScope.launch { // 连接设备 uwbManager.connect(device, applicationContext) // 监听该设备的测距结果 uwbManager.rangingResult.collect { result -> when (result) { is EstimoteUWBRangingResult.Position -> { // 仅处理当前设备的结果 if (result.device.address == device.address) { val position = result.position val positionInfo = "Position of ${result.device.address} : Distance=${position.distance?.value}, Azimuth=${position.azimuth?.value}, Elevation=${position.elevation?.value}" Log.d("UWBResult", positionInfo) } } is EstimoteUWBRangingResult.PeerDisconnected -> { Log.d("UWBResult", "Device disconnected: ${result.device.address}") } else -> { // 处理其他结果类型 } } } } } fun onRegisterClick(view: View) { val intent = Intent(this, SignUpActivity::class.java) startActivity(intent) } override fun onDestroy() { super.onDestroy() // 停止扫描和连接,释放资源 lifecycleScope.launch { uwbManager.stopDeviceScanning() // 若SDK提供断开所有连接的API,此处调用 } } }
额外建议
- 若SDK支持配置测距Profile,尝试查找是否有
setRangingProfile或类似方法,设置为支持多设备的模式。 - 检查Beacon的固件版本,确保所有Beacon处于同一固件版本,避免兼容性问题。
- 增加错误处理逻辑,捕获
connect方法可能抛出的异常,排查连接失败的具体原因。
内容的提问来源于stack exchange,提问作者Davide Paolillo
相关产品推荐
相关产品推荐

