Android Studio中Kotlin请求蓝牙扫描/连接权限遭拒求解决方案
Kotlin中正确请求Android 12+蓝牙权限的实现方式
你的代码始终提示权限被拒,核心问题在于未在AndroidManifest.xml中正确声明权限,同时缺少对用户拒绝权限且勾选“不再询问”场景的处理。以下是完整的正确实现步骤:
1. 配置AndroidManifest.xml权限
必须在清单文件中声明所需蓝牙权限,同时兼容旧版本系统:
<manifest ...> <!-- Android 12以下版本的蓝牙权限(仅兼容用) --> <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" /> <!-- Android 12+ 核心蓝牙权限 --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <!-- 若无需通过蓝牙获取位置,添加此flag避免位置权限要求 --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" /> <!-- 声明设备蓝牙支持(可选,若App允许无蓝牙设备运行,添加required="false") --> <uses-feature android:name="android.hardware.bluetooth" android:required="true" /> <uses-feature android:name="android.hardware.bluetooth_le" android:required="false" /> <application ...> ... </application> </manifest>
2. 修正Activity权限请求逻辑
添加权限合理性提示,以及处理用户拒绝权限且“不再询问”的场景,引导用户前往设置页开启权限:
class MainActivity : AppCompatActivity() { // 多权限请求处理 private val requestMultiplePermissions = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions -> permissions.entries.forEach { (permission, isGranted) -> Log.d("test", "$permission = $isGranted") if (!isGranted) { when { // 用户拒绝且勾选不再询问,引导去设置页 !shouldShowRequestPermissionRationale(permission) -> { val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { data = Uri.fromParts("package", packageName, null) } startActivity(intent) Toast.makeText(this, "请在设置中开启蓝牙权限", Toast.LENGTH_LONG).show() } // 用户拒绝但未勾选不再询问,提示权限重要性 else -> { Toast.makeText(this, "${permission}权限被拒绝,部分功能无法使用", Toast.LENGTH_SHORT).show() } } } } } // Android 12以下启用蓝牙的请求处理 private val requestEnableBluetooth = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> if (result.resultCode == RESULT_OK) { Toast.makeText(this, "蓝牙已启用", Toast.LENGTH_SHORT).show() } else { Toast.makeText(this, "蓝牙启用被拒绝", Toast.LENGTH_SHORT).show() } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val button = findViewById<Button>(R.id.button) button.setOnClickListener { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { // Android 12+ 请求蓝牙扫描与连接权限 requestMultiplePermissions.launch( arrayOf( Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT ) ) } else { // Android 11及以下,直接请求启用蓝牙(旧版本蓝牙权限安装时授予) val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE) requestEnableBluetooth.launch(enableBtIntent) } } } }
额外注意事项
- 如果App需要通过蓝牙扫描获取位置(如蓝牙信标定位),不能添加
neverForLocationflag,此时还需根据系统版本请求ACCESS_FINE_LOCATION或ACCESS_COARSE_LOCATION权限。 - 权限请求必须由用户交互触发(如按钮点击),不能在Activity启动时自动发起,否则系统可能直接拒绝请求。
内容的提问来源于stack exchange,提问作者AdamPI
相关产品推荐
相关产品推荐

