记录一些描述
# SSE报告
在 TROPS 智能足球 App 中,我负责开发 AI 数据分析报告模块,主要用于根据球员比赛数据生成 AI 训练分析报告,包括比赛复盘、训练建议等内容。
这个模块的核心需求是 AI 报告生成时间较长,不能让用户一直等待,所以采用了 SSE(Server-Sent Events)流式通信方案,实现 AI 内容实时返回,类似 ChatGPT 的逐字输出效果。
技术实现上,前端通过接口发起 AI 报告生成请求,后端返回 reportId,之后客户端根据 reportId 建立 SSE 长连接,持续接收 AI 生成的数据片段,并实时渲染到页面。
在流式展示过程中,我没有直接每次收到数据就更新 React State,因为 AI 返回频率比较高,会导致大量组件重渲染,影响性能。因此设计了一个 buffer 缓冲机制,将 SSE 返回的数据先暂存在 ref 中,然后通过定时 flush 的方式(约 300ms)批量更新 UI,降低渲染压力。
同时针对移动端网络环境不稳定的问题,增加了断线恢复机制:
- 监听网络状态变化,区分在线、离线状态;
- SSE 连接异常时,根据重试次数采用递增延迟策略重新连接;
- 通过保存 lastSeq 游标,避免断线重连后数据重复或者丢失;
- 支持生成中的报告恢复,通过 snapshot 接口获取当前生成状态。
另外针对 AI 返回 Markdown 内容实时渲染的问题,对流式文本进行了处理:
- 处理 Markdown 标签未闭合导致的渲染异常;
- 对代码块、加粗符号等未完成状态进行兼容;
- 将完整内容和正在生成中的尾部文本拆分,保证用户看到稳定内容的同时继续展示生成过程。
在交互方面,实现了:
- Tab 多类型报告切换;
- 自动滚动到最新生成内容;
- AI报告截图保存分享;
- 多语言适配。
这个模块主要解决了三个问题:
- AI 长耗时任务的实时反馈体验;
- 移动端弱网络环境下的稳定性;
- 高频数据更新带来的性能问题。
最终实现了类似 AI 对话的流式生成体验,同时保证了 App 在 Android/iOS 双端运行时的稳定性。
# BLE
在 TROPS 智能足球脚环项目中,我负责 BLE 蓝牙通信模块的设计和开发,主要实现 App 与硬件脚环之间的数据交互,通过蓝牙采集球员训练和比赛过程中的运动数据,并在 App 内进行展示和分析。
由于 React Native 本身无法直接访问底层蓝牙能力,所以项目中采用 React Native + Native BLE 能力结合的方式实现。我基于 react-native-ble-manager 封装了一层 BLE Manager,对外提供统一的蓝牙接口,包括设备扫描、连接、断开、数据读取、数据写入以及监听设备状态变化。
整体架构上,我将蓝牙模块设计成单例模式,保证整个 App 生命周期内只有一个蓝牙连接管理实例,避免多个页面重复创建连接导致状态混乱。
在数据通信流程上:
首先 App 会扫描附近 BLE 设备,通过设备名称和 Service UUID、Characteristic UUID 过滤目标脚环设备。
用户选择设备后建立 BLE 连接,并进行服务发现,获取对应的读写特征。
连接成功后:
- 通过 Notify 方式监听设备主动上报的数据;
- 通过 Write Characteristic 向设备发送控制指令;
- 对收到的二进制数据进行解析,转换成业务需要的运动数据模型。
由于 BLE 通信存在弱连接、不稳定等问题,我重点处理了连接稳定性:
- 连接状态管理: 维护设备连接状态,包括扫描中、连接中、已连接、断开等状态,避免页面状态和真实设备状态不一致。
- 自动重连机制: 当设备因为距离、干扰等原因断开时,会监听 disconnect 事件,根据设备状态尝试重新连接,并恢复数据监听。
- 数据接收优化: BLE 数据通常是二进制分包传输,所以增加数据缓存和拼包处理逻辑,避免单次通知数据不完整导致解析错误。
- 异常处理: 针对蓝牙权限关闭、系统蓝牙关闭、设备连接失败等情况增加异常提示和恢复流程,提高用户体验。
另外,在 RN 与原生交互方面,我也参与了 Android/iOS Native Module 集成,将部分底层能力通过 Native Bridge 暴露给 JS 层,例如蓝牙权限处理、设备状态监听等。
最终实现了 App 与足球脚环稳定通信,支持实时采集训练数据,并应用到 AI 分析、比赛报告等业务场景。
# BLE hook
在 BLE 模块开发过程中,除了底层蓝牙通信封装之外,我进一步将业务层常用的蓝牙能力封装成 React Hooks,降低页面和蓝牙底层逻辑的耦合,提高代码复用性。
因为项目中多个页面都会涉及设备连接、数据采集、设备状态展示,如果每个页面都直接调用 BLE API,会导致大量重复代码,同时连接状态、监听事件也容易出现管理混乱的问题。
所以我设计了一层 Hook 封装,将 BLE 能力抽离出来,对业务页面提供更加简单的调用方式。
主要包括:
- 设备连接 Hook
封装设备扫描、连接、断开等流程。
页面只需要调用类似 connectDevice(device) 的方法,不需要关注底层 BLE API 调用过程,包括 Service Discover、Characteristic 获取等细节。
- 数据监听 Hook
针对脚环实时上传的数据,封装 Notify 监听逻辑。
Hook 内部负责:
- 注册蓝牙通知监听;
- 接收硬件返回的二进制数据;
- 数据解析转换;
- 监听生命周期清理。
业务层直接获取格式化后的运动数据,例如速度、控球、传射等指标。
- 蓝牙状态管理 Hook
统一维护设备状态,例如:
- 未连接
- 扫描中
- 连接中
- 已连接
- 断开
- 重连中
避免不同页面自己维护状态导致 UI 展示不一致。
- 数据发送 Hook
针对设备控制指令,例如开始采集、停止采集、同步数据等操作,封装统一发送方法。
内部处理:
- 数据格式转换;
- Write Characteristic 调用;
- 发送失败重试。
另外,在 Hook 内部结合 useRef 管理一些不会影响 UI 的实时状态,例如当前连接设备、BLE listener、timer 等,避免频繁 setState 导致页面重复渲染。
同时在 useEffect 中处理生命周期:
- 页面进入时初始化监听;
- 页面销毁时移除 BLE listener;
- 断开连接时释放资源。
最终形成了一套类似:
页面层 ↓ useBLEDevice / useBLEData Hook ↓ BLE Manager 单例 ↓ react-native-ble-manager ↓ Native Bluetooth API
的分层结构。
这样业务页面只关注业务逻辑,不需要关心蓝牙通信细节,提高了代码可维护性和后续扩展能力。