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"
  }
}

相关推荐
蒸鱼Yuzheng6 小时前
设备端性能工件可靠导出:断点续传、哈希、manifest 与失败恢复
android·自动化测试·python·adb·数据完整性
美狐美颜sdk8 小时前
直播APP接入美颜SDK后出现卡顿怎么办?从性能瓶颈寻找解决方案
android·人工智能·音视频·美颜sdk·直播美颜sdk
美狐美颜SDK开放平台8 小时前
直播APP开发实战:从摄像头调用到视频美颜sdk集成
android·人工智能·计算机视觉·音视频·直播美颜sdk
alexhilton9 小时前
生命周期感知的多模块启动模式
android·kotlin·android jetpack
三少爷的鞋10 小时前
Android 架构指南:suspend 如何响应取消?别再给 Repository 加 `cancel()`
android
迪飞特科技11 小时前
【无标题】
android·人工智能·本地化大模型
FlightYe11 小时前
视界原理之2D视频(二):视频文件里有什么
android·linux·网络·c++·ffmpeg·音视频·aac
传奇开心果编程11 小时前
【Flutter入门练中学】第8课:动画与过渡
android·学习·flutter·ui·ios
传奇开心果编程13 小时前
【Flutter入门练中学】第11课:状态管理进阶与声明式路由
android·学习·flutter·ui·ios
JasonSJX14 小时前
四端自建播放器怎么落地:Android、iOS、tvOS、Tizen 的 DRM 播放 SDK 技术盘点
android·ios·音视频·视频防录屏·加密保护课程·直播安全