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
相关产品推荐
相关产品推荐

