create-react-native-app蓝牙开发指南:与硬件设备通信

create-react-native-app蓝牙开发指南:与硬件设备通信

【免费下载链接】create-react-native-app Create React Native apps that run on iOS, Android, and web 【免费下载链接】create-react-native-app 项目地址: https://gitcode.com/gh_mirrors/cr/create-react-native-app

你是否在使用create-react-native-app开发蓝牙应用时遇到设备连接不稳定、数据传输延迟或权限配置混乱等问题?本文将从环境搭建到实际通信,手把手教你使用react-native-ble-plx库实现手机与硬件设备的稳定通信,读完后你将掌握:蓝牙设备扫描、连接管理、数据读写的完整流程,以及iOS/Android双平台权限配置技巧。

开发环境准备

安装蓝牙依赖库

react-native-ble-plx是目前React Native生态中最成熟的蓝牙开发库,支持BLE(Bluetooth Low Energy,蓝牙低功耗)设备通信。通过create-react-native-app创建的项目需先安装该依赖:

# 使用npm安装
npm install react-native-ble-plx --save

# 或使用yarn安装
yarn add react-native-ble-plx

平台权限配置

蓝牙功能需要配置系统权限,不同平台的配置方式不同:

iOS平台配置
  1. ios/项目名/Info.plist中添加蓝牙权限描述:
<key>NSBluetoothAlwaysUsageDescription</key>
<string>需要蓝牙权限以连接智能硬件设备</string>
<key>UIBackgroundModes</key>
<array>
  <string>bluetooth-central</string> <!-- 允许后台蓝牙通信 -->
</array>
  1. 确保Xcode中开启蓝牙后台模式:
  • 打开ios/项目名.xcworkspace
  • 进入项目设置 → Signing & Capabilities → 添加Background Modes
  • 勾选Uses Bluetooth LE Accessories
Android平台配置
  1. android/app/src/main/AndroidManifest.xml中添加权限:
<!-- 基础蓝牙权限 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- Android 12+ 蓝牙权限 -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- 位置权限(用于蓝牙扫描) -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
  1. android/build.gradle中确保最低SDK版本不低于23:
buildscript {
  ext {
    minSdkVersion = 23 // BLE功能要求至少API 23
  }
}

蓝牙通信核心流程

初始化蓝牙管理器

创建BluetoothManager.ts封装蓝牙操作,通过BleManager类初始化蓝牙客户端:

import { BleManager, Device } from 'react-native-ble-plx';

class BluetoothManager {
  private manager: BleManager;

  constructor() {
    // 初始化蓝牙管理器
    this.manager = new BleManager({
      restoreStateIdentifier: 'ble-manager-state',
      restoreStateFunction: (state) => {
        // 恢复蓝牙连接状态(用于应用重启后重连)
        if (state) {
          console.log('蓝牙状态已恢复', state);
        }
      }
    });
  }

  // 检查蓝牙是否开启
  async checkBluetoothEnabled(): Promise<boolean> {
    const state = await this.manager.state();
    return state === 'PoweredOn';
  }
}

export const bluetoothManager = new BluetoothManager();

扫描蓝牙设备

使用startDeviceScan方法扫描周围的BLE设备,需注意扫描会消耗设备电量,建议设置超时自动停止:

// 在BluetoothManager类中添加扫描方法
async scanDevices(timeoutMs: number = 5000): Promise<Device[]> {
  return new Promise((resolve, reject) => {
    const devices: Device[] = [];
    const scanSubscription = this.manager.startDeviceScan(
      null, // 扫描所有服务UUID的设备(传入特定UUID可过滤设备)
      { allowDuplicates: false }, // 不重复返回已发现设备
      (error, device) => {
        if (error) {
          scanSubscription.remove();
          reject(error);
          return;
        }
        if (device && !devices.some(d => d.id === device.id)) {
          devices.push(device);
          console.log('发现设备:', device.name, device.id);
        }
      }
    );

    // 超时后停止扫描
    setTimeout(() => {
      scanSubscription.remove();
      resolve(devices);
    }, timeoutMs);
  });
}

连接蓝牙设备

扫描到设备后,通过设备ID建立连接,连接过程需处理可能的异常(如设备超出范围、连接超时等):

// 在BluetoothManager类中添加连接方法
async connectToDevice(deviceId: string): Promise<Device> {
  try {
    const device = await this.manager.connectToDevice(deviceId, {
      autoConnect: false, // 不自动重连(需要时手动处理)
      timeout: 15000 // 15秒连接超时
    });
    // 连接成功后发现设备服务
    await device.discoverAllServicesAndCharacteristics();
    return device;
  } catch (error) {
    console.error('设备连接失败:', error);
    throw error;
  }
}

读写设备数据

BLE设备通过GATT(Generic Attribute Profile)协议通信,数据存储在"特征值(Characteristic)"中,读写流程如下:

// 读取特征值数据
async readCharacteristic(
  deviceId: string,
  serviceUuid: string,
  characteristicUuid: string
): Promise<Buffer> {
  const device = await this.manager.getDevice(deviceId);
  const characteristic = await device.readCharacteristicForService(
    serviceUuid,
    characteristicUuid
  );
  return characteristic.value as Buffer; // 数据以Buffer格式返回
}

// 写入数据到特征值
async writeCharacteristic(
  deviceId: string,
  serviceUuid: string,
  characteristicUuid: string,
  data: Buffer
): Promise<void> {
  const device = await this.manager.getDevice(deviceId);
  await device.writeCharacteristicWithoutResponseForService(
    serviceUuid,
    characteristicUuid,
    data.toString('base64') // 数据需转换为base64字符串
  );
}

完整通信示例

以下是一个连接温湿度传感器并读取数据的完整示例,假设传感器的服务UUID为0000FFB0-0000-1000-8000-00805F9B34FB,特征值UUID为0000FFB2-0000-1000-8000-00805F9B34FB

// 温湿度传感器通信示例
async function readTemperatureHumidity() {
  try {
    // 1. 检查蓝牙是否开启
    const isEnabled = await bluetoothManager.checkBluetoothEnabled();
    if (!isEnabled) {
      console.log('请开启蓝牙');
      return;
    }

    // 2. 扫描设备(超时5秒)
    const devices = await bluetoothManager.scanDevices(5000);
    const sensorDevice = devices.find(d => d.name?.includes('TempSensor'));
    if (!sensorDevice) {
      console.log('未找到温湿度传感器');
      return;
    }

    // 3. 连接设备
    await bluetoothManager.connectToDevice(sensorDevice.id);

    // 4. 读取温湿度数据
    const serviceUuid = '0000FFB0-0000-1000-8000-00805F9B34FB';
    const characteristicUuid = '0000FFB2-0000-1000-8000-00805F9B34FB';
    const data = await bluetoothManager.readCharacteristic(
      sensorDevice.id,
      serviceUuid,
      characteristicUuid
    );

    // 5. 解析数据(假设数据格式为:温度(2字节小端) + 湿度(2字节小端))
    const temperature = data.readInt16LE(0) / 10; // 温度值,精度0.1℃
    const humidity = data.readInt16LE(2) / 10; // 湿度值,精度0.1%
    console.log(`当前温度: ${temperature}℃, 湿度: ${humidity}%`);

  } catch (error) {
    console.error('通信失败:', error);
  }
}

常见问题解决方案

设备连接不稳定

  • 问题原因:蓝牙信号受环境干扰,或设备进入休眠模式
  • 解决方法
    1. 实现连接状态监听,断线时自动重连:
    device.onDisconnected((error, device) => {
      console.log('设备已断开连接,尝试重连...');
      this.connectToDevice(device.id); // 调用之前实现的连接方法
    });
    
    1. 增加扫描功率(仅Android支持):
    await this.manager.setScanMode(2); // 2表示高功率扫描
    

数据传输缓慢

  • 问题原因:默认MTU(Maximum Transmission Unit,最大传输单元)值较小(通常20字节)
  • 解决方法:协商更大的MTU值(最大512字节):
async negotiateMtu(deviceId: string, mtu: number = 512): Promise<number> {
  const device = await this.manager.getDevice(deviceId);
  return device.requestMtu(mtu);
}

权限申请被拒

  • 问题原因:用户拒绝授予位置或蓝牙权限
  • 解决方法:使用react-native-permissions库检查并请求权限:
import { check, request, PERMISSIONS, RESULTS } from 'react-native-permissions';

async requestBluetoothPermissions() {
  if (Platform.OS === 'ios') {
    const result = await check(PERMISSIONS.IOS.BLUETOOTH_ALWAYS);
    if (result !== RESULTS.GRANTED) {
      await request(PERMISSIONS.IOS.BLUETOOTH_ALWAYS);
    }
  } else {
    // Android需要位置和蓝牙权限
    await request(PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION);
    await request(PERMISSIONS.ANDROID.BLUETOOTH_SCAN);
  }
}

总结与展望

本文介绍了使用create-react-native-app和react-native-ble-plx库开发蓝牙应用的核心流程,包括设备扫描、连接管理、数据读写等关键步骤,并提供了跨平台权限配置和常见问题解决方案。蓝牙开发中,设备兼容性和环境干扰是主要挑战,建议在多台设备上测试,并实现完善的错误处理机制。

未来,你可以进一步探索:

  • 蓝牙广播包解析(用于识别设备类型)
  • 低功耗优化(如批量发送数据、合理设置扫描间隔)
  • 复杂设备的多特征值协同操作

希望本文能帮助你顺利开发出稳定可靠的蓝牙应用,如有疑问欢迎在评论区留言讨论!

点赞收藏本文,关注作者获取更多React Native开发技巧,下期将分享蓝牙设备OTA固件升级实战教程。

【免费下载链接】create-react-native-app Create React Native apps that run on iOS, Android, and web 【免费下载链接】create-react-native-app 项目地址: https://gitcode.com/gh_mirrors/cr/create-react-native-app

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值