android 蓝牙连接-兼容旧版本

react-native-ble-manager 扫描结果突然变成 空数组 ,通常不是代码逻辑问题,而是 权限 / 系统策略 / BLE 设备广播变化。你这段代码本身逻辑是没问题的。常见原因主要有下面几类(按概率排序):


1️⃣ Android 12+ 蓝牙权限变化(最常见)

如果你的 targetSdkVersion ≥ 31 (Android 12) ,必须增加新的蓝牙权限,否则 scan 会成功执行但返回空设备。

AndroidManifest.xml 必须增加

复制代码
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />

兼容旧版本:

复制代码
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

同时需要运行时权限

React Native 代码:

复制代码
import {PermissionsAndroid} from 'react-native';

async function requestPermissions() {
  await PermissionsAndroid.requestMultiple([
    PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
    PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
    PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
  ]);
}

启动 BLE 前调用:

复制代码
await requestPermissions();

否则:

复制代码
getDiscoveredPeripherals() = []

2️⃣ 没有监听

BleManagerDiscoverPeripheral

事件

BleManager.getDiscoveredPeripherals() 依赖 扫描事件缓存。

新版 Android 有时不会自动缓存。

建议监听事件:

复制代码
import {NativeEventEmitter, NativeModules} from 'react-native';

const bleManagerEmitter = new NativeEventEmitter(NativeModules.BleManager);

bleManagerEmitter.addListener(
  'BleManagerDiscoverPeripheral',
  (peripheral) => {
    console.log('discover', peripheral);
  }
);

如果这里 没有任何输出

说明 scan 根本没有发现设备。


3️⃣ 打印机不再广播 name

很多 BLE 打印机升级固件后:

复制代码
peripheral.name = null

设备名称在:

复制代码
peripheral.advertising.localName

所以建议改为:

复制代码
const printer = peripherals.find(
  p =>
    p.name === printerName ||
    p.advertising?.localName === printerName
);

4️⃣ scan 参数问题

你现在:

复制代码
BleManager.scan([], 5, true);

第三个参数 true 是 allowDuplicates

建议改成:

复制代码
BleManager.scan([], 5, false);

有些 Android 会过滤。


5️⃣ Android 没打开定位

Android BLE 扫描必须开启:

复制代码
Location Service

否则:

复制代码
scan = []

6️⃣ iOS 17 / Android 13 扫描策略改变

如果是新系统:

扫描必须:

复制代码
BleManager.start({showAlert: false})

在扫描前调用:

复制代码
await BleManager.start({showAlert: false});

7️⃣ 你的 timeout 可能太短

你扫描:

复制代码
scan 5 秒
timeout 6 秒

建议:

复制代码
scan 8 秒
timeout 9 秒

推荐改进代码

复制代码
_scan(printerName) {
  return new Promise(async (resolve, reject) => {
    try {

      await BleManager.start({showAlert:false})

      console.log('===========> scanAndConnect');

      await BleManager.scan([], 8, false);

      setTimeout(async () => {
        try {

          const peripherals = await BleManager.getDiscoveredPeripherals();

          console.log('peripherals', peripherals);

          const printer = peripherals.find(p =>
            p.name === printerName ||
            p.advertising?.localName === printerName
          );

          resolve(printer);

        } catch (e) {
          console.log('_scan get device failed', e);
          reject(e);
        }

      }, 9000);

    } catch (e) {
      console.log('_scan failed', e);
      reject(e);
    }
  });
}

8️⃣ 最关键的排查方法(强烈推荐)

先打印:

复制代码
console.log(JSON.stringify(peripherals,null,2))

看真实返回结构。

很多时候你会看到:

复制代码
{
  "name": null,
  "advertising": {
    "localName": "Printer_123"
  }
}

相关推荐
alexhilton12 小时前
Room Fts4:全文搜索替代 SQL LIKE
android·kotlin·android jetpack
hai_android17 小时前
把 Android App 打包成系统应用(System App)
android·kotlin·android jetpack
JMchen18 小时前
【Jetpack 内核实战 01】开篇:Jetpack 组件全家桶核心逻辑与专栏完整规划
android·kotlin·android jetpack
骑着蜗牛撵大象32719 小时前
Linux 进程间通信之管道:从 pipe() 的内核语义到 FIFO 落地排错
android·java·linux·系统编程·fifo·管道·进程间通信
hunterandroid20 小时前
Retrofit 网络请求的异常处理与重试策略实战
android
sejinan20 小时前
极致轻量与秒级起播:NativeWasmTv 开源硬核技术解析与升级版体验
android·开源·webview·tv
小羊没烦恼!20 小时前
Ajax与JSON的一些总结
android·java·前端·数据库·mysql·算法·okhttp
mmsx21 小时前
Android 静默失败实录:五个没有日志的线上事故
android·kotlin
hai_android21 小时前
从零实现一个支持跨进程(IPC)的自定义 Toast
android·kotlin·android jetpack
龙腾-虎跃1 天前
基于 SIP 协议的自研电话终端:FreeSWITCH 语音与视频通信实战
android·音视频·freeswitch·sip协议终端·wertc