You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 03:12:03