一、跨平台蓝牙开发,到底选哪个?
说实话,这个问题我几乎每个月都会被问到。不管是刚入行的新人,还是想从原生转跨平台的老手,大家最纠结的就是:Flutter、React Native、还是原生Android?
我在蓝牙领域摸爬滚打了七八年,踩过的坑比写过的代码还多。今天我就把这三个方案掰开揉碎了讲清楚。你想想看,选错了方案,后面改起来有多痛苦?我见过一个项目,用Flutter做了一半发现蓝牙扫描不稳定,最后全部推翻重写原生——那叫一个惨。
1.1 三个方案的核心差异
先看一张对比图,心里有个底:
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