实践记录:React Native 与物理测试设备的串口通信方案实现
最近在做一个关于物理体质健康测试设备(如身高体重秤、肺活量计)的项目,核心难点在于如何稳定地处理 Android 原生串口与 React Native 业务层之间的数据交换。
这类项目通常涉及多个硬件同时工作,对实时性和稳定性要求极高。在折腾了一段时间后,我整理了一套基于 React Native 的双串口通信架构,在这里记录一下实现细节。
1. 整体架构设计
为了保证数据的流转清晰,我将通信链路拆解为以下几个层次:
硬件设备 ↔ Android 系统文件 (/dev/ttyS*) ↔ Android 原生模块 (Kotlin) ↔ React Native Bridge ↔ React Context Provider ↔ UI 界面。
在 React 侧,我主要通过以下几个组件进行管理:
DualSerialPortModule: 封装了 Android 原生接口。MultiSerialPortManager: 核心管理器,处理开关、波特率配置及自动重连。SerialPortProvider: 全局 Context,统一分发串口状态。useDualSerialPort: 业务钩子,方便在页面中订阅数据和发送指令。
2. 核心功能实现
多串口并发管理
由于测试环境通常需要多个设备协作,系统需要支持同时操作多个串口。目前我配置了三个常用通道:
- BMI 串口: 负责身高体重,19200 波特率。
- 肺活量串口: 4800 波特率。
- 打印机串口: 负责结果输出。
灵活的读取模式
不同的硬件驱动特性各异,为了兼容性,我设计了两种模式:
- 可用性检查模式 (
available()-based):数据到达时按块读取,非常适合肺活量计这种 ASCII 文本流。 - 直接/阻塞模式 (Direct/Blocking):适用于身高体重秤这种需要稳定、实时连续数据流的设备。
稳定性保障机制
- 权限自修复:在打开串口前,系统会尝试执行
su -c chmod 666,解决 Android 系统常见的设备文件权限不足问题。 - 异常重连:设置了 3 秒自动重连机制,应对震动或接触不良导致的物理断连。
- 看门狗 (Watchdog):为了防止硬件长时间运行进入死机状态,系统每 30 秒会自动发送一次
0xEE指令“喂狗”。
3. 通信协议的适配
处理串口数据最头疼的就是协议不同。在这个项目中,我主要处理了两类截然不同的协议:
身高体重 (二进制协议)
采用 帧头 + 长度 + 指令 + 数据 的格式。这种格式必须严格校验每一帧的完整性,防止粘包。
肺活量 (ASCII 文本协议)
通过简单的文本响应,如 VC OK 或 VCDAT1:4000。这类协议解析起来相对简单,但需要处理好字符串的拼接。
4. 业务层的集成
为了不让业务逻辑和底层通信搅在一起,我利用 React 的 Hook 模式将功能解耦:
- 实时 UI 更新:在测试页面直接监听数据流,实时显示进度条或当前数值。
- 语音交互同步:数据解析完成后,自动触发
useTTS进行播报,比如:“测试完成,肺活量 4000 毫升”。 - 状态监控:通过全局状态感知硬件在线情况,连接失败时及时弹出 Toast 提示。
5. 一些开发心得(技术点复盘)
在实现这套方案的过程中,有几点尝试让我觉得效果不错,也踩了一些坑:
- 关于原生实现的思考:
最初考虑过用 NDK/JNI 编译 C++ 的串口库,但考虑到项目维护成本,最终选择了纯 Kotlin 实现。通过反射调用
libcore.io.Libcore和stty命令进行配置,虽然绕了一点,但极大地简化了构建流程,在性能上也完全满足需求。 - 数据解析的细节:
串口通信中粘包、拆包是家常便饭。我基于
Buffer做了二进制帧的拼接和校验,确保只有完整的包才会传递给 JS 侧。这虽然多写了一些逻辑,但避免了后续业务层出现各种奇葩的解析错误。 - 开发者体验的优化:
我尽量把复杂的 native 通信细节“藏”起来。对业务开发者来说,只需要调用
write和监听onDataReceived即可。这种声明式的用法让后续维护的人(也包括几个月后的我自己)能快速上手。
总结
串口通信在 React Native 中虽然算是一个比较边缘的领域,但只要把底层协议和上层状态管理好,依然能做出非常丝滑的硬件交互体验。
最后更新:2026年3月13日
标签:ReactNative、串口通信、硬件交互、Android开发
最近更新:3/13/2026, 9:30:36 AM