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

Android 11及以下版本React Native Bluetooth Classic设备发现异常问题

问题原因分析
  1. 权限请求逻辑不兼容低版本
    Android 11(API 30)及以下不存在BLUETOOTH_SCAN和BLUETOOTH_CONNECT权限,尝试请求这些不存在的权限时,系统会直接返回NEVER_ASK_AGAIN。你的权限判断逻辑将该状态等同于授权通过,但实际位置权限可能未正确获取,导致扫描因权限不足卡住。
  2. startDiscovery调用方式问题
    低版本Android中蓝牙扫描依赖位置权限,若权限未完全授予,startDiscovery会静默阻塞而非抛出异常;此外,部分版本中该方法需配合事件监听完成扫描,直接用await可能导致主线程冻结。
解决办法

1. 修复权限请求逻辑,按Android版本区分权限

根据系统版本动态构建需要请求的权限列表,避免在低版本请求不存在的蓝牙权限:

import { Platform } from 'react-native';

const getNeededPermissions = () => {
  const permissions = [];
  if (Platform.Version >= 31) {
    // Android 12+ 请求新蓝牙权限
    permissions.push(
      'android.permission.BLUETOOTH_SCAN',
      'android.permission.BLUETOOTH_CONNECT'
    );
  } else {
    // Android 11及以下 请求位置权限(蓝牙扫描依赖)
    permissions.push(
      'android.permission.ACCESS_FINE_LOCATION',
      'android.permission.ACCESS_COARSE_LOCATION'
    );
    // BLUETOOTH和BLUETOOTH_ADMIN属于正常权限,无需动态请求
  }
  return permissions;
};

const requestAccessFineLocationPermission = async () => {
  const neededPermissions = getNeededPermissions();
  const granted = await PermissionsAndroid.requestMultiple(neededPermissions);

  let isGranted = true;
  if (Platform.Version >= 31) {
    isGranted = granted['android.permission.BLUETOOTH_SCAN'] === PermissionsAndroid.RESULTS.GRANTED &&
                granted['android.permission.BLUETOOTH_CONNECT'] === PermissionsAndroid.RESULTS.GRANTED;
  } else {
    isGranted = granted['android.permission.ACCESS_FINE_LOCATION'] === PermissionsAndroid.RESULTS.GRANTED &&
                granted['android.permission.ACCESS_COARSE_LOCATION'] === PermissionsAndroid.RESULTS.GRANTED;
  }

  setGranted(isGranted);
};

2. 调整设备发现逻辑,增加权限校验与事件监听

调用startDiscovery前先确保权限已授予,改用事件监听处理扫描结果,避免await阻塞主线程:

import { DeviceEventEmitter } from 'react-native';

let discoveryListener = null;

const startDeviceDiscovery = async () => {
  const available = await RNBluetoothClassic.isBluetoothAvailable();
  const enabled = await RNBluetoothClassic.isBluetoothEnabled();

  if (!available || !enabled) {
    await RNBluetoothClassic.requestBluetoothEnabled();
    return;
  }

  // 先校验权限是否已授予
  if (!granted) {
    await requestAccessFineLocationPermission();
    if (!granted) {
      console.log("权限不足,无法扫描设备");
      setLoading(false);
      return;
    }
  }

  try {
    setLoading(true);
    setLoadingText('正在扫描设备...');

    // 先获取已配对设备
    const paired = await RNBluetoothClassic.getBondedDevices();
    setAvailableDevices([...paired]);

    // 注册扫描事件监听,接收新发现的未配对设备
    if (discoveryListener) {
      discoveryListener.remove();
    }
    discoveryListener = DeviceEventEmitter.addListener(
      'BLUETOOTH_DISCOVERY',
      (device) => {
        // 避免重复添加设备
        setAvailableDevices(prev => {
          const exists = prev.some(d => d.address === device.address);
          return exists ? prev : [...prev, device];
        });
      }
    );

    // 启动扫描
    await RNBluetoothClassic.startDiscovery();
    
    // 扫描10秒后自动停止
    setTimeout(async () => {
      await RNBluetoothClassic.stopDiscovery();
      if (discoveryListener) {
        discoveryListener.remove();
        discoveryListener = null;
      }
      setLoading(false);
      setLoadingText('');
    }, 10000);

  } catch (err) {
    console.log(err);
    setLoading(false);
    setLoadingText('');
    if (discoveryListener) {
      discoveryListener.remove();
      discoveryListener = null;
    }
  }
};

3. 优化AndroidManifest配置(可选)

确保新蓝牙权限仅对高版本生效,避免低版本系统混淆:

<!-- Request Bluetooth permissions for devices on API 31+ -->
<uses-permission
    android:name="android.permission.BLUETOOTH_SCAN"
    android:usesPermissionFlags="neverForLocation"
    android:maxSdkVersion="33" />
<uses-permission 
    android:name="android.permission.BLUETOOTH_CONNECT"
    android:maxSdkVersion="33" />

内容的提问来源于stack exchange,提问作者Valentin Emil Cudelcu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 05:14:54