海狸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. 用户体验是核心:技术最终是为用户服务的,所有的技术选型都应该以提升用户体验为目标。

相关链接

项目源码:

学习资源:

核心教学视频:

相关推荐
张风捷特烈2 小时前
GetX 之死 | 8 年从未用过,以后将不会再用
android·前端·flutter
「、皓子~3 小时前
Flutter赋能海狸IM:打造高性能跨平台移动体验
flutter
阿里加多10 小时前
第 4 章:Go 线程模型——GMP 深度解析
java·开发语言·后端·golang
GDAL11 小时前
Go Channel 深入全面讲解教程
golang
见山是山-见水是水11 小时前
鸿蒙flutter第三方库适配 - 儿童故事
flutter·华为·harmonyos
2401_8396339113 小时前
鸿蒙flutter第三方库适配 - URL处理应用
flutter·华为·harmonyos
止语Lab14 小时前
Go GC 十年:一部延迟战争史
golang
阿里加多14 小时前
第 1 章:Go 并发编程概述
java·开发语言·数据库·spring·golang
李李李勃谦14 小时前
Flutter 框架跨平台鸿蒙开发 - 星空日记
flutter·华为·harmonyos