Android 12及以上版本切换蓝牙连接时应用崩溃问题求助
解决Android 12+切换蓝牙连接时的崩溃问题
核心问题分析
Android 12(API 31)及以上版本对蓝牙权限体系做了拆分,BLUETOOTH_SCAN和BLUETOOTH_CONNECT属于危险权限,仅在Manifest中声明静态权限不足以正常使用蓝牙功能,必须动态申请权限。此外,扫描蓝牙设备前未确保权限已授予,是触发崩溃的主要原因。
解决方案步骤
1. 新增动态权限申请逻辑
先创建权限请求的ActivityResultLauncher,用于在需要时申请蓝牙相关权限:
// 根据系统版本定义需要申请的蓝牙权限 private val BLUETOOTH_PERMISSIONS = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { arrayOf( Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT ) } else { arrayOf(Manifest.permission.BLUETOOTH) } // 权限请求Launcher private val permissionLauncher = registerForActivityResult( ActivityResultContracts.RequestMultiplePermissions() ) { permissions -> val allGranted = permissions.all { it.value } if (allGranted) { // 权限全部授予后,继续执行蓝牙开启流程 bluetoothEnabler.launch(BluetoothUtils.turnBluetoothOn()) } else { hideProgress() Toast.makeText(appActivity, "需要蓝牙权限才能继续操作", Toast.LENGTH_SHORT).show() } }
2. 修改蓝牙选择对话框触发流程
在showBtSelectDialog中,先检查权限状态,未授予则发起申请,再执行蓝牙开启操作:
private fun showBtSelectDialog() { lifecycleScope.launch { lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) { showProgress() // 检查当前是否已拥有蓝牙权限 val hasPermissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { ContextCompat.checkSelfPermission(appActivity, Manifest.permission.BLUETOOTH_SCAN) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(appActivity, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED } else { ContextCompat.checkSelfPermission(appActivity, Manifest.permission.BLUETOOTH) == PackageManager.PERMISSION_GRANTED } if (hasPermissions) { bluetoothEnabler.launch(BluetoothUtils.turnBluetoothOn()) } else { // 发起权限申请 permissionLauncher.launch(BLUETOOTH_PERMISSIONS) } } } }
3. 确保设备扫描与连接前权限有效
在showBtSelectDialogInternal中,二次校验权限,避免用户在申请后手动拒绝导致崩溃:
private fun showBtSelectDialogInternal() { // 检查扫描权限 val hasScanPermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { ContextCompat.checkSelfPermission(appActivity, Manifest.permission.BLUETOOTH_SCAN) == PackageManager.PERMISSION_GRANTED } else { true // 低版本无需单独扫描权限 } if (!hasScanPermission) { Toast.makeText(appActivity, "需要蓝牙扫描权限才能搜索设备", Toast.LENGTH_SHORT).show() return } ListSelectDialog.Builder<IODevice, LayoutSelectItemListBinding>(appActivity) .apply { title(R.string.select_bt_device) applyItemLayout(R.layout.layout_select_item_list) applyFunction { binding, dialog -> IODeviceHolder(dialog, binding) { // 连接前检查蓝牙连接权限 val hasConnectPermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { ContextCompat.checkSelfPermission(appActivity, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED } else { true } if (hasConnectPermission) { model.selectedConnectionChange(ConnectionType.BT, it) handleVisibilityElements(ConnectionType.BT) } else { Toast.makeText(appActivity, "需要蓝牙连接权限才能连接设备", Toast.LENGTH_SHORT).show() } } } applyList(appActivity.resolveBTDevices().map { IODevice.parse(it) }) headerIcon(R.drawable.ic_bluetooth) titleColor(Helper.uiModeDialogColors(isDarkMode)) headerIconColor(Helper.uiModeDialogColors(isDarkMode)) dialogBackgroundColor(Helper.uiModeDialogColors(isDarkMode)) tintAll(R.color.iconBlue) }.create().show(childFragmentManager, null) }
4. 确认蓝牙开启Intent正确性
确保BluetoothUtils.turnBluetoothOn()返回标准的蓝牙开启请求Intent:
fun turnBluetoothOn(): Intent { return Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE) }
内容的提问来源于stack exchange,提问作者Fishu 85
相关产品推荐
相关产品推荐

