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

Android 12触发java.lang.SecurityException:需BLUETOOTH_CONNECT权限

解决Android 12蓝牙连接的java.lang.SecurityException异常

问题原因

Android 12(API 31)及以上版本对蓝牙权限做了细分,BLUETOOTH_CONNECT是新增的危险权限,调用connectGatt这类蓝牙连接API前必须获取该权限,否则会抛出SecurityException。

解决方案

1. 在AndroidManifest.xml中声明权限

添加权限声明以兼容不同Android版本:

<!-- Android 12及以上所需权限 -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- Android 11及以下所需旧权限 -->
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />

<!-- 蓝牙LE功能声明 -->
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
<!-- Android 10及以下蓝牙扫描所需位置权限 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" />

2. 运行时动态申请BLUETOOTH_CONNECT权限

在调用蓝牙连接逻辑前,先检查并申请权限:

private val BLUETOOTH_CONNECT_REQUEST_CODE = 1001

// 检查蓝牙连接权限是否已授予
private fun hasBluetoothConnectPermission(): Boolean {
    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED
    } else {
        // Android 11及以下无需此权限,直接返回true
        true
    }
}

// 发起蓝牙连接权限申请
private fun requestBluetoothConnectPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        ActivityCompat.requestPermissions(
            this,
            arrayOf(Manifest.permission.BLUETOOTH_CONNECT),
            BLUETOOTH_CONNECT_REQUEST_CODE
        )
    }
}

// 处理权限申请结果
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    if (requestCode == BLUETOOTH_CONNECT_REQUEST_CODE) {
        if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // 权限授予成功,重新执行蓝牙连接
            connect(mBluetoothDeviceAddress)
        } else {
            Toast.makeText(this, "需要蓝牙连接权限才能继续操作", Toast.LENGTH_SHORT).show()
        }
    }
}

3. 修改connect方法,增加前置检查

在调用connectGatt前加入权限和蓝牙状态检查:

fun connect(address: String?): Boolean {
    if (mBluetoothAdapter == null || address == null) {
        return false
    }

    // 检查蓝牙是否开启
    if (!mBluetoothAdapter.isEnabled) {
        Toast.makeText(this, "请先开启蓝牙", Toast.LENGTH_SHORT).show()
        return false
    }

    // 检查权限,未授予则发起申请
    if (!hasBluetoothConnectPermission()) {
        requestBluetoothConnectPermission()
        return false
    }

    try {
        if (BluetoothAdapter.checkBluetoothAddress(address)) {
            device = mBluetoothAdapter.getRemoteDevice(address)
        } else {
            Toast.makeText(this, "无效的MAC地址", Toast.LENGTH_LONG).show()
            return false
        }
    } catch (e: IllegalArgumentException) {
        e.printStackTrace()
        return false
    } catch (e: IllegalStateException) {
        e.printStackTrace()
        return false
    }

    if (device == null) {
        return false
    }

    mBluetoothGatt = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        device.connectGatt(
            this, false, mGattCallback,
            BluetoothDevice.TRANSPORT_LE
        )
    } else {
        device.connectGatt(this, false, mGattCallback)
    }
    Log.d(TAG, "尝试创建新连接")

    mBluetoothDeviceAddress = address
    mConnectionState = STATE_CONNECTING
    return true
}

注意事项

  • Android 12及以上版本,BLUETOOTH_CONNECT必须动态申请,仅在Manifest声明无效。
  • 若需在后台执行蓝牙连接,需确保应用处于前台状态,或针对旧版本申请ACCESS_BACKGROUND_LOCATION权限。

内容的提问来源于stack exchange,提问作者lakshmi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 08:25:15