海狸IM技术升级:从Uniapp到Flutter的跨平台重构之路

海狸IM技术升级:从Uniapp到Flutter的跨平台重构之路

做IM应用这几年,最开始用Uniapp写移动端,随着持续的迭代,一些技术瓶颈逐渐凸显。从Uniapp到Flutter的重构,不是心血来潮,而是深思熟虑后的选择。

为什么要换

性能瓶颈

IM应用的核心是消息,消息量大的时候渲染性能就成了瓶颈。在Uniapp里,消息列表一旦超过几百条,往上滑就开始卡顿,特别是有图片和表情的时候。用户截图发过来,加载速度也不太理想,经常出现图片加载中、消息发送中这些状态长时间不消失的情况。

Flutter的渲染机制不同。它直接调用Skia引擎绘制UI,不存在WebView或者原生控件的桥接损耗。实际跑起来,消息列表滑动的流畅度明显上一个台阶,即使是2000条消息的列表,滑动起来依然顺滑。

音视频功能缺失

原本的版本里一直没有音视频通话功能,这是用户反馈最多的需求之一。但Uniapp做实时音视频的方案,要么依赖原生插件,要么用WebRTC的Web实现,两种方案我都试过:

  • 原生插件:调试麻烦,打包流程复杂,而且跨平台维护成本高,Android和iOS需要分别处理不同的插件版本
  • WebRTC Web方案:性能损耗明显,通话质量不理想,特别是在网络不好的情况下

Flutter这边有成熟的LiveKit客户端 livekit_client,直接对接LiveKit服务,音视频通话的实现反而比想象中顺利。从发起通话到接通,整个流程的体验和原生应用差不多。

本地存储局限

Uniapp的本地存储方案,核心是key-value结构,比如uni.setStorage。对于IM这种需要频繁查询、结构复杂的数据,不太够用。消息多了之后,查询历史消息、按会话分组等操作都变得很慢。

Flutter这边我用了Drift(原名 Moor),它是SQLite的ORM方案,可以写类型安全的SQL查询。本地消息缓存、联系人列表、群组信息都可以做本地持久化,离线也能看历史消息,联网后自动同步增量数据。

跨平台维护成本

Uniapp写一次跑多端听起来美好,但实际开发中总会遇到各端兼容性问题,需要写不少条件编译。比如微信小程序的API限制、H5的浏览器差异、原生App的权限处理,这些都需要单独处理。

Flutter虽然也有平台通道,但整体一致性更好,一套代码改动的调试成本低很多。特别是在UI层面,Flutter的跨平台表现几乎一致,不用为不同平台做太多适配。

技术方案的选择

Flutter版本

我用的是Flutter 3.x + Dart 3.x。这个组合的 null safety 和新语法特性让代码质量更有保障,减少了运行时错误。

依赖这块,核心的几个:

  • flutter_bloc: ^9.1.1 # 状态管理
  • go_router: ^17.1.0 # 路由
  • drift: ^2.32.0 # SQLite ORM
  • livekit_client: ^2.6.5 # 音视频通话
  • dio: ^5.9.2 # HTTP客户端
  • web_socket_channel: ^3.0.3 # WebSocket

项目结构

参考了官方推荐的项目结构,按功能模块组织:

复制代码
lib/
├── core/                     # 核心基础设施
│   ├── business/            # 业务逻辑实现
│   ├── database/            # 本地数据库
│   ├── datasync/            # 数据同步
│   └── message/             # 消息处理
├── features/                # 业务模块
│   ├── auth/                # 登录注册
│   ├── chat/                # 聊天
│   ├── friend/              # 好友
│   ├── group/               # 群组
│   └── call/                # 音视频通话
├── shared/                  # 共享组件
└── di/                      # 依赖注入

分层清晰的好处是改需求的时候影响范围可控,不会牵一发而动全身。

本地数据库设计

消息表是最核心的一张表,和PC端保持一致。字段设计包括消息ID、会话ID、消息类型、发送状态等,支持离线重试和消息排序。

音视频通话实现

这块是全新加的功能。Flutter端通过LiveKit实现,后端需要搭建LiveKit服务。核心流程:

  1. 用户发起通话 → 调用后端API创建room
  2. 获取token和room信息
  3. Flutter端连接LiveKit房间
  4. 订阅远端用户的音视频轨道

重写过程中的坑

状态管理选型

一开始纠结用Provider还是BLoC,最后选了BLoC。它的单向数据流在复杂业务场景下更好维护,测试也方便。不过Bloc的代码量确实多些,这是取舍。

WebSocket重连

IM应用里WebSocket断线重连是刚需。Flutter端实现了心跳机制和自动重连,消息发送有ACK确认,超时重试。这块逻辑参考了商业IM的设计,确保消息的可靠传递。

多端数据同步

Flutter端和已有的PC端共用同一个后端API,数据格式必须一致。同步策略是增量拉取+本地优先,减少网络请求,提升用户体验。

性能优化

Flutter虽然性能好,但也需要优化:

  • 消息列表用ListView.builder,避免一次性渲染所有消息
  • 图片用CachedNetworkImage,减少重复请求
  • 状态管理用BLoC,避免不必要的重建
  • 数据库查询加索引,提升查询速度

重构前后对比

性能对比

场景 Uniapp Flutter
消息列表滑动 卡顿(500条消息) 流畅(2000条消息)
图片加载 较慢,经常显示占位符 快速,本地缓存命中率高
启动速度 3-5秒 2-3秒
音视频通话 不支持 支持,质量稳定

功能对比

功能 Uniapp Flutter
文本消息 支持 支持
图片消息 支持 支持
表情消息 支持 支持
音视频通话 不支持 支持
离线消息 有限支持 完整支持
本地缓存 key-value存储 SQLite数据库

现在的状态

重构后的Flutter版本已经接替了原来的Uniapp版本,成为海狸IM的移动端主力。音视频通话、本地消息缓存、表情收藏这些之前难做的功能,现在都跑起来了。

当然,Flutter不是银弹。它的包体积比H5大,首页启动速度在低端机上不如原生。这些都是后续优化方向。

重构经验总结

  1. 技术选型要匹配需求:如果你的应用需要高性能、复杂功能,Flutter是个好选择;如果只是轻量应用,Uniapp可能更合适。

  2. 重写不是坏事:有时候重构比在旧代码上打补丁更高效,特别是当技术栈已经成为瓶颈时。

  3. 分层设计很重要:清晰的项目结构让后续维护和扩展更轻松。

  4. 性能优化不能忽视:即使是Flutter,也需要合理的优化才能达到最佳效果。

  5. 用户体验是核心:技术最终是为用户服务的,所有的技术选型都应该以提升用户体验为目标。

相关链接

项目源码:

学习资源:

核心教学视频:

相关推荐
codeejun1 天前
每日一Go-59、云原生入门为什么一定要学Docker?
docker·云原生·golang
初心未改HD1 天前
gRPC 与 Protobuf 实战指南
开发语言·golang
jieyucx1 天前
Go语言切片:动态灵活的数据序列
算法·golang·指针·顺序表·数组·结构体·切片
Eric_HYD1 天前
Flutter 字体字生效原理解析
flutter
maaath1 天前
【无标题】Flutter for OpenHarmony 的文具手账应用开发实践
flutter·华为·harmonyos
里欧跑得慢1 天前
Flutter 主题管理:构建一致的用户界面
前端·css·flutter·web
初心未改HD1 天前
Go 文件与 I/O 操作完全指南
开发语言·golang
RuoyiOffice1 天前
SpringBoot+Vue3 实现 OA 公文外来文与归档台账:外部收文、BPM办理、三类公文统一归档
spring boot·微服务·uni-app·vue·ruoyi·anti-design-vue·ruoyioffice
geovindu1 天前
go: Mediator Pattern
设计模式·golang·中介者模式
liulian09162 天前
Flutter for OpenHarmony 跨平台开发:单位转换功能实战指南
flutter