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

Android 12+设备BLE扫描崩溃问题技术求助

Android 12目标版本下Android 11设备BLE扫描崩溃问题排查与解决

我是Haia Consultancy的实习生,使用Kotlin开发Android应用。当前应用targetSDK设为32(对应Android 12),在S21+(Android 11)设备上执行BLE扫描时应用崩溃,低版本Android设备无此问题。错误日志提示需要android.permission.BLUETOOTH_SCAN权限,我已按官方指南配置Manifest权限、申请位置权限,甚至直接使用Android 12+适配的官方示例代码,仍然报错。检查权限时,BLUETOOTH_SCAN返回-1,尝试多种方案无效。最后发现将权限检查改为BLUETOOTH_CONNECT后代码可正常运行,但不清楚原因,求问问题根源及解决方法。

错误日志

2022-12-07 16:01:45.692 28797-28797 AndroidRuntime
    com...e.ultrawidebandproofofconcept  E  FATAL EXCEPTION: main
        Process: com.example.ultrawidebandproofofconcept, PID: 28797
        java.lang.SecurityException: Need android.permission.BLUETOOTH_SCAN permission for AttributionSource { uid = 10366, packageName = com.example.ultrawidebandproofofconcept, attributionTag = null, token = android.os.BinderProxy@ff32c8f, next = null }: GattService registerScanner
            at android.os.Parcel.createExceptionOrNull(Parcel.java:2438)
            at android.os.Parcel.createException(Parcel.java:2422)
            at android.os.Parcel.readException(Parcel.java:2405)
            at android.os.Parcel.readException(Parcel.java:2347)
            at android.bluetooth.IBluetoothGatt$Stub$Proxy.registerScanner(IBluetoothGatt.java:1886)
            at android.bluetooth.le.BluetoothLeScanner$BleScanCallbackWrapper.startRegistration(BluetoothLeScanner.java:519)
            at android.bluetooth.le.BluetoothLeScanner.startScan(BluetoothLeScanner.java:305)
            at android.bluetooth.le.BluetoothLeScanner.startScan(BluetoothLeScanner.java:161)
            at com.example.ultrawidebandproofofconcept.MainActivity.startBleScan(MainActivity.kt:96)
            at com.example.ultrawidebandproofofconcept.MainActivity.onCreate$lambda-0(MainActivity.kt:80)
            at com.example.ultrawidebandproofofconcept.MainActivity.$r8$lambda$NQsLDkI5TsYB6INH-F0JwBK_SNM(Unknown Source:0)
            at com.example.ultrawidebandproofofconcept.MainActivity$$ExternalSyntheticLambda2.onClick(Unknown Source:2)
            at android.view.View.performClick(View.java:7792)
            at android.widget.TextView.performClick(TextView.java:16112)
            at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1219)
            at android.view.View.performClickInternal(View.java:7769)
            at android.view.View.access$3800(View.java:910)
            at android.view.View$PerformClick.run(View.java:30218)
            at android.os.Handler.handleCallback(Handler.java:938)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loopOnce(Looper.java:226)
            at android.os.Looper.loop(Looper.java:313)
            at android.app.ActivityThread.main(ActivityThread.java:8751)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)

已尝试方案

  • 申请ACCESS_FINE_LOCATION/ACCESS_COARSE_LOCATION权限
  • 在Manifest中声明BLE扫描无需关联位置信息(添加android:usesPermissionFlags="neverForLocation")
  • 使用Android官方提供的Android 12+ BLE适配示例代码

崩溃代码

if (ActivityCompat.checkSelfPermission(
        this,
        Manifest.permission.BLUETOOTH_SCAN
    ) != PackageManager.PERMISSION_GRANTED
) {
    requestPermissionLauncher.launch(
        Manifest.permission.BLUETOOTH_SCAN
    )
    requestPermissionLauncher.launch(
        Manifest.permission.BLUETOOTH_CONNECT
    )
    return
}
bleScanner.startScan(null, scanSettings, scanCallback)

可行代码

if (ActivityCompat.checkSelfPermission(
        this,
        Manifest.permission.BLUETOOTH_CONNECT
    ) != PackageManager.PERMISSION_GRANTED
) {
    requestPermissionLauncher.launch(
        Manifest.permission.BLUETOOTH_SCAN
    )
    requestPermissionLauncher.launch(
        Manifest.permission.BLUETOOTH_CONNECT
    )
    return
}
bleScanner.startScan(null, scanSettings, scanCallback)

问题根源

这是targetSDK版本与运行设备系统版本的权限兼容性冲突导致的:

  1. BLUETOOTH_SCAN是Android 12新增的危险权限,当应用targetSDK=32时,系统要求动态申请该权限;但Android 11及以下系统中不存在这个权限,ActivityCompat.checkSelfPermission检查该权限会直接返回PERMISSION_DENIED(即-1)。
  2. 崩溃代码中,因BLUETOOTH_SCAN检查未通过,进入权限申请逻辑,但Android 11系统无法识别该权限,导致requestPermissionLauncher无法弹出对应的授权对话框,权限始终无法被授予,后续执行startScan时触发SecurityException。
  3. 可行代码中检查的BLUETOOTH_CONNECT同样是Android 12新增权限,但在Android 11中,系统会将该权限检查映射为旧的BLUETOOTH权限(Android 11及以下中,BLE扫描仅需BLUETOOTH和位置权限)。若已在Manifest中声明旧版BLUETOOTH权限,系统会判定BLUETOOTH_CONNECT权限已授予,跳过申请逻辑直接执行扫描,此时设备已具备所需权限,扫描正常运行。

解决方法

正确的做法是根据运行设备的系统版本,区分权限检查与申请逻辑:

val isAndroid12OrHigher = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
val hasRequiredPermission = if (isAndroid12OrHigher) {
    ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) == PackageManager.PERMISSION_GRANTED &&
    ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED
} else {
    ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH) == PackageManager.PERMISSION_GRANTED &&
    ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
}

if (!hasRequiredPermission) {
    val permissionsToRequest = if (isAndroid12OrHigher) {
        arrayOf(Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT)
    } else {
        arrayOf(Manifest.permission.BLUETOOTH, Manifest.permission.ACCESS_FINE_LOCATION)
    }
    requestPermissionLauncher.launch(permissionsToRequest)
    return
}
bleScanner.startScan(null, scanSettings, scanCallback)

同时,确保Manifest中同时声明新旧权限,覆盖不同系统版本:

<!-- 旧版本Android权限(Android 11及以下) -->
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30"/>

<!-- Android 12+权限 -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>

<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 05:31:33