一、跨平台蓝牙开发,到底选哪个?

说实话,这个问题我几乎每个月都会被问到。不管是刚入行的新人,还是想从原生转跨平台的老手,大家最纠结的就是:Flutter、React Native、还是原生Android?

我在蓝牙领域摸爬滚打了七八年,踩过的坑比写过的代码还多。今天我就把这三个方案掰开揉碎了讲清楚。你想想看,选错了方案,后面改起来有多痛苦?我见过一个项目,用Flutter做了一半发现蓝牙扫描不稳定,最后全部推翻重写原生——那叫一个惨。

1.1 三个方案的核心差异

先看一张对比图,心里有个底:

蓝牙跨平台方案对比总览 Flutter React Native 原生Android flutter_blue / flutter_blue_plus ✅ 跨平台代码复用率高 ✅ Dart语言上手快 ⚠️ 蓝牙库维护参差不齐 ⚠️ 低功耗蓝牙扫描不稳定 ❌ 无法直接操作HCI层 ❌ 多设备连接性能差 react-native-ble-plx ✅ JavaScript生态丰富 ✅ 热重载开发效率高 ⚠️ 蓝牙桥接层性能损耗 ⚠️ 线程模型复杂 ❌ 原生模块依赖多 ❌ 调试困难 android.bluetooth.* ✅ 完全控制蓝牙协议栈 ✅ 性能最优 ✅ 支持所有蓝牙Profile ✅ 可做系统级开发 ⚠️ 开发周期长 ⚠️ 需要处理碎片化 我的建议: 简单BLE外设 → Flutter | 复杂多设备 → 原生 | 已有RN项目 → RN

1.2 Flutter + flutter_blue:快速原型的好帮手

Flutter做蓝牙开发,最大的优势就是一套代码跑两端。我去年帮一个创业团队做智能灯控App,从零到上线只用了三周。用flutter_blue_plus扫描、连接、读写特征值,一气呵成。

核心代码示例(Flutter):

// 扫描蓝牙设备
FlutterBluePlus.instance.startScan(
  withServices: [Guid("180F")], // 电池服务
  scanMode: ScanMode.lowLatency,
);

// 监听扫描结果
FlutterBluePlus.instance.scanResults.listen((results) {
  for (ScanResult r in results) {
    print('发现设备: ${r.device.name} - ${r.rssi}dBm');
  }
});

但是,别高兴太早。我在项目中遇到过一个问题:flutter_blue在Android 12上扫描经常漏设备。后来查了半天,发现是库没有正确处理新的蓝牙权限模型。你想想看,如果生产环境出现这种问题,用户投诉起来多麻烦?

避坑指南:

我曾经因为flutter_blue的扫描回调延迟,导致一个医疗设备项目差点延期。后来改用flutter_blue_plus(社区维护版)才解决。记住:选库要看维护活跃度,别用那种半年不更新的。

1.3 React Native + react-native-ble-plx:JS生态的诱惑

React Native的优势在于前端开发者转型成本低。如果你团队里都是React高手,用RN做蓝牙开发确实快。react-native-ble-plx这个库写得不错,API设计很清晰。

核心代码示例(React Native):

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

const manager = new BleManager();

// 扫描设备
manager.startDeviceScan(
  null, // 不限制服务UUID
  null, // 不限制扫描选项
  (error, device) => {
    if (error) {
      console.error('扫描失败:', error);
      return;
    }
    console.log(`发现: ${device.name} (${device.id})`);
  }
);

但说实话,RN做蓝牙有个硬伤——桥接层性能损耗。我记得有一次做心率监测App,需要实时读取心率数据。在原生上延迟只有20ms,到了RN上直接飙到100ms+。为什么?因为每次数据都要从Java层桥接到JS层,这个开销逃不掉。

我的经验:

如果只是做简单的开关控制、状态读取,RN完全够用。但如果是高频数据交互(比如音频传输、实时传感器),我建议你还是老老实实用原生。

1.4 原生Android开发:性能王者,但代价不低

原生开发,说白了就是直接操作Android蓝牙协议栈。你能拿到最底层的控制权,想怎么玩就怎么玩。我做过一个项目,需要同时连接8个蓝牙设备并保持低延迟通信——这种场景,跨平台方案根本扛不住。

核心代码示例(原生Android):

// 获取蓝牙适配器
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();

// 开始扫描
adapter.startLeScan(new BluetoothAdapter.LeScanCallback() {
    @Override
    public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
        Log.d("BLE", "发现: " + device.getName() + " RSSI: " + rssi);
    }
});

// 连接设备
BluetoothGatt gatt = device.connectGatt(context, false, gattCallback);

但是,原生开发也有它的痛点。Android碎片化问题你躲不掉——不同厂商的蓝牙芯片实现不一样,华为、小米、三星各有各的毛病。我曾在某款国产手机上遇到GATT连接后立刻断开的问题,查了三天才发现是厂商修改了蓝牙协议栈的默认参数。

避坑指南:

我曾经在适配某款低端手机时,发现它的蓝牙芯片不支持同时扫描和连接。这种问题在跨平台框架里根本没法处理,只能写原生代码做特殊适配。所以,如果目标用户覆盖大量低端机,原生开发几乎是唯一选择

1.5 选型决策表

说了这么多,到底怎么选?我整理了一个决策表,你对照着看:

场景 推荐方案 理由
简单BLE外设控制(灯、锁、传感器) Flutter 开发快,跨平台,基本功能够用
已有React Native项目需要加蓝牙 React Native 复用现有技术栈,减少学习成本
多设备同时连接(3个以上) 原生Android 性能要求高,跨平台扛不住
高频数据交互(音频、实时传感器) 原生Android 延迟敏感,必须底层优化
需要自定义蓝牙Profile 原生Android 跨平台框架不支持自定义Profile
快速原型验证 Flutter / RN 迭代快,改起来方便
企业级复杂蓝牙应用 原生Android 稳定性和可控性优先

1.6 我的最终建议

嗯,说了这么多,总结一下我的个人看法:

  • 如果你在创业公司或者做MVP,用Flutter快速出活,别纠结性能。等用户量上来了再考虑重写原生部分。
  • 如果你在成熟产品团队,核心蓝牙功能用原生写,UI层可以跨平台。我见过不少团队采用这种混合架构——原生做蓝牙引擎,Flutter/RN做界面。
  • 如果你做的是系统级蓝牙开发(比如车载、物联网网关),别想了,直接上原生。跨平台框架连HCI层都碰不到,更别说做协议栈优化了。

一个小技巧:

不管你选哪个方案,先把蓝牙权限和扫描逻辑在原生层封装好。这样即使以后换框架,底层代码也能复用。我现在的项目都是这么干的——原生层提供AIDL接口,上层随便用什么框架调用。

好了,这一章就到这里。记住:没有最好的方案,只有最合适的方案。下一章我会深入讲Android蓝牙权限适配,这可是个坑多到数不清的话题,到时候见。


公众号:蓝海资料掘金营,微信deep3321