
本文由阿里闲鱼技术团队祈晴分享,本次有修订和改动,感谢作者的技术分享。
1、内容概述本文总结了阿里闲鱼技术团队使用Flutter在对闲鱼IM进行移动端跨端改造过程中的技术实践等,文中对比了传统Native与现在大热的Flutter跨端方案在一些主要技术实现上的差异,以及针对Flutter技术特点的具体技术实现,值得同样准备使用Flutter开发IM的技术同行们借鉴和参考。
学习交流:
- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM》- 开源IM框架源码:>
(本文同步发布于:>2、闲鱼IM现状
闲鱼IM的移动端框架构建于2016至2017年间,期间经过多次迭代升级导致历史包袱累积多,后面又经历IM界面的Flutter化,从而造成了客户端架构愈加复杂。
从开发层面总结闲鱼IM移动端当前架构主要存在如下几个问题:
1)研发效率较低:当前架构涉及到Android/iOS双端的逻辑代码以及Flutter的UI代码,定位问题往往只能从Flutter UI表相倒查到Native逻辑层;2)架构层次较差:架构设计上分层不清晰,业务逻辑夹杂在核心的逻辑层致使代码变更风险大;3)性能测试略差:核心数据源存储Native内存,需经Flutter Plugin将数据源序列化上抛Flutter侧,在大批量数据源情况下性能表现较差。从产品层面总结闲鱼IM移动端当前架构的主要问题如下:
1)定位问题困难:线上舆情反馈千奇百怪,测试始终无法复现相关场景,因此很多时候只能靠现象猜测本质;2)疑难杂症较多:架构的不稳定性造成出现的问题反复出现,当前疑难杂症主要包括未读红点计数、iPhone5C低端机以及多媒体发送等多个问题;3)问题差异性大:Android和iOS两端逻辑代码差异大,包括埋点逻辑都不尽相同,排查问题根源时双端都会有不同根因,解决方案也不相同。3、业界的移动端跨端方案为解决当前IM的技术痛点,闲鱼今年特起关于IM架构升级项目,重在解决客户端中Andriod和iOS双端一致性的痛点,初步设想方案就是实现跨端统一的Android/iOS逻辑架构。
在当前行业内跨端方案可初步归类如下图架构:
在GUI层面的跨端方案有Weex、ReactNative、H5、Uni-APP等,其内存模型大多需要通过桥接到Native模式存储。
在逻辑层面的跨端方案大致有C/C++等与虚拟机无关语言实现跨端,当然汇编语言也可行。
此外有两个独立于上述体系之外的架构就是Flutter和KMM(谷歌基于Kotlin实现类似Flutter架构),其中Flutter运行特定DartVM,将内存数据挂载其自身的isolate中。
考虑闲鱼是Flutter的前沿探索者,方案上优先使用Flutter。然而Flutter的isolate更像一个进程的概念(底层实现非使用进程模式),相比Android,同一进程场景中,Android的Dalvik虚拟机多个线程运行共享一个内存Heap,而DartVM的Isolate运行隔离各自的Heap,因而isolate之间通讯方式比较繁琐(需经过序列化反序列化过程)。
整个模型如下图所示:
若按官方混合架构实现Flutter应用,开启多个FlutterAcitivty/FlutterController,底层会生成多个Engine,对应会存在多个isolate,而isolate通讯类似于进程通讯(类似socket或AIDL),这里借鉴闲鱼FlutterBoost的设计理念,FlutterIM架构将多个页面的Engine共享,则内存模型就天然支持共享读取。
原理图如下:
4、闲鱼IM基于Flutter的架构设计41 新老架构对比
如下图所示:是一个老架构方案,其核心问题主要集中于Native逻辑抽象差,其中逻辑层面还设计到多线程并发使得问题倍增,Android/iOS/Flutter交互繁杂,开发维护成本高,核心层耦合较为严重,无插拔式概念
考虑到历史架构的问题,演进如下新架构设计:
如上图所示,架构从上至下依次为:
1)业务层;2)分发层;3)逻辑层;4)数据源层。数据源层来源于推送或网络请求,其封装于Native层,通过Flutter插件将消息协议数据上抛到Flutter侧的核心逻辑层,处理完成后变成Flutter DB的Enitity实体,实体中挂载一些消息协议实体。
核心逻辑层将繁杂数据扁平化打包挂载到分发层中的会话内存模型数据或消息内存模型数据,最后通过观察者模式的订阅分发到业务逻辑中。
Flutter IM重点集中改造逻辑层和分发层,将IM核心逻辑和业务层面数据模型进行封装隔离,核心逻辑层和数据库交互后将数据封装到分发层的moduleData中,通过订阅方式分发到业务层数据模型中。
此外在IM模型中DB也是重点依赖的,个人对DB数据库管理进行全面封装解,实现一种轻量级,性能佳的Flutter DB管理框架。
42 DB存储模型
Flutter IM架构的DB存储依赖数据库插件,目前主流插件是Sqflite。
其存储模型如下:
依据上图Sqflite插件的DB存储模型会有2个等待队列:
一个是Flutter层同步执行队列;一个是Native层的线程执行队列。其Android实现机制是HandlerThread,因此Query/Save读写在会同一线程队列中,导致响应速度慢,容易造成DB SQL堆积,此外缺失缓存模型。
于是个人定制如下改进方案:
Flutter侧通过表的主键设计查询时候会优先从Entity Cache层去获取,若缓存不存在,则通过Sqflite插件查询。
同时改造Sqflite插件成支持sync/Async同步异步两种方式 *** 作,对应到Native侧也会有同步线程队列和异步线程队列,保证数据吞吐率。但是这里建议查询使用异步,存储使用同步更稳妥,主要怕出现多个相同的数据元model同一时间进入异步线程池中,存储先后顺序无法有效的保证。
43 ORM数据库方案
IM架构重度依赖DB数据库,而当前业界还没有一个完备的数据库ORM管理方案,参考了Android的OrmLite/GreenDao,个人自行设计一套Flutter ORM数据库管理方案。
其核心思想如下:
由于Flutter不支持反射,因此无法直接像Android的开源数据库方式 *** 作,但可通过APT方式,将Entity和Orm Entity绑定于一身, *** 作OrmEntity即 *** 作Entity,整个代码风格设计也和OrmLite极其相似。
参考代码如下:
44 IM内存数据模型
基于Flutter的IM移动端架构在内存数据模型主要划分为会话和消息两个颗粒度:
1)会话内存数据模型交托于SessionModuleData:会话内存数据有一个根节点RootNotice,然后其挂载PSessionMessageNotice(这里PSessionMessageNotice是ORM映射的会话DB表模型)子节点集合。2)消息内存数据模型交托于MessageModuleData:消息内存数据会有一个MessageConatiner容器管理,其内部挂载此会话中的PMessage(PMessage是ORM映射的消息DB表模型)消息集合。依据上一章节,PSessionMessageNotice设计了一个OrmEnitity Cache,考虑到IM中会话数是有限的,因此PSessionMessageNotice都是直接缓存到Cache中。
这种做法的好处是各地去拿会话数据元时候都是缓存中同一个对象,容易保证多次重复读写的数据一致性。而PSessionMessageNotice考虑到其数量可以无限多的特殊性,因此这里将其挂载到MessageContainer的内存管理中,在退出会话的时机会校验容器中PMessage集合的数量,适当缩容可以减少内存开销。
模型如下图所示:
45 状态管理方案
基于Flutter的IM移动端架构状态管理方案比较简单,对数据源Session/Message维度使用观察者模式的订阅分发方式实现,架构类似于EventBus模式,页面级的状态管理无论使用fish-redux、scopeModel或者provider几乎影响面不大,核心还是需保留一种插拔式抽象更重要。
架构如下图:
46 IM同步模型方案
当前现状的消息同步模型:
如上图所示是,模型中存在ACCS Thread/Main Thread/Region Thread等多线程并发场景,导致易出现多线程高并发的问题。
native的推送和网络请求同步的隔离方案通过Lock的锁机制,并且通过队列降频等方式处理,流程繁琐且易出错。整体通过Region Version Gap去判断是否有域空洞,进而执行域同步补充数据。
改进的同步模型如下:
如上图所示,在Flutter侧天然没多线程场景,通过一种标记位的转化同步异步实现类似Handler消息队列,架构清晰简约了很多,避免锁带来的开销以及同步问题。
5、本次改造进展以及性能对比1)针对架构层面:
在基于Flutter的IM架构中,重点将双端逻辑差异性统一成同一份Dart代码,完全磨平Android/iOS的代码差异性带来的问题。
带来的好处很明显:
1)降低开发维护、测试回归、视觉验收的一半成本,极大提高研发效率;2)架构上进行重构分层,实现一种解耦合,插拔式的IM架构;3)同时Native到Flutter侧的大量数据上抛序列化过程改造程Flutter引用传递,解决极限测试场景下的私聊卡顿问题。2)针对线上舆情:
1)补齐UT和TLog的集团日志方式做到可追踪,可排查;2)针对于很多现存的疑难杂症重点集中专项解决,比如iphone5C的架构在Flutter侧统一规划;3)未读红点计数等问题也在架构模型升级中修复;4)此外多媒体音视频发送模块进行改造升级。3)性能数据对比:
当IM架构的逻辑层和UI层都切换成Flutter后,和原先架构模式初步对比,整体内存水位持平。
其中:
1)私聊场景下小米9测试结构内存下降40M,功耗降低4mah,CPU降低1%;2)极限测试场景下新架构内存数据相比于旧架构有一个较为明显的改观(主要由于两个界面都使用Flutter场景下,页面切换的开销降低很多)。6、未来展望JS跨端不安全,C++跨端成本有点高,Flutter会是一个较好选择。彼时闲鱼FlutterIM架构升级根本目的从来不是因Flutter而Flutter,是由于历史包袱的繁重,代码层面的维护成本高,新业务的扩展性差,人力配比不协调以及疑难杂症的舆情持续反馈等等因素造成我们不得不去探索新方案。
经过闲鱼IM超复杂业务场景验证Flutter模式的逻辑跨端可行性,闲鱼在Flutter路上会一直保持前沿探索,最后能反馈到生态圈。
总结一句话,探索过程在于你勇于迈出第一步,后面才会不断惊喜发现。
(原文链接:点此进入,本次有修订和改动)
附录:更多文章汇总[1] 更多阿里团队的文章分享:《阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处》
《现代IM系统中聊天消息的同步和存储方案探讨》
《阿里技术分享:深度揭秘阿里数据库技术方案的10年变迁史》
《阿里技术分享:阿里自研金融级数据库OceanBase的艰辛成长之路》
《来自阿里OpenIM:打造安全可靠即时通讯服务的技术实践分享》
《钉钉——基于IM技术的新一代企业OA平台的技术挑战(视频+PPT) [附件下载]》
《阿里技术结晶:《阿里巴巴Java开发手册(规约)-华山版》[附件下载]》
《重磅发布:《阿里巴巴Android开发手册(规约)》[附件下载]》
《作者谈《阿里巴巴Java开发手册(规约)》背后的故事》
《《阿里巴巴Android开发手册(规约)》背后的故事》
《干了这碗鸡汤:从理发店小弟到阿里P10技术大牛》
《揭秘阿里、腾讯、华为、百度的职级和薪酬体系》
《淘宝技术分享:手淘亿级移动端接入层网关的技术演进之路》
《难得干货,揭秘支付宝的2维码扫码技术优化实践之路》
《淘宝直播技术干货:高清、低延时的实时视频直播技术解密》
《阿里技术分享:电商IM消息平台,在群聊、直播场景下的技术实践》
《阿里技术分享:闲鱼IM基于Flutter的移动端跨端改造实践》
[2] 更多IM开发综合文章:
《新手入门一篇就够:从零开发移动端IM》
《移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”》
《移动端IM开发者必读(二):史上最全移动弱网络优化方法总结》
《从客户端的角度来谈谈移动端IM的消息可靠性和送达机制》
《现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障》
《移动端IM中大规模群消息的推送如何保证效率、实时性?》
《移动端IM开发需要面对的技术问题》
《开发IM是自己设计协议用字节流好还是字符流好?》
《IM消息送达保证机制实现(一):保证在线实时消息的可靠投递》
《IM消息送达保证机制实现(二):保证离线消息的可靠投递》
《如何保证IM实时消息的“时序性”与“一致性”?》
《一个低成本确保IM消息时序的方法探讨》
《IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?》
《IM群聊消息如此复杂,如何保证不丢不重?》
《谈谈移动端 IM 开发中登录请求的优化》
《移动端IM登录时拉取数据如何作到省流量?》
《浅谈移动端IM的多点登录和消息漫游原理》
《完全自已开发的IM该如何设计“失败重试”机制?》
《通俗易懂:基于集群的移动端IM接入层负载均衡方案分享》
《微信对网络影响的技术试验及分析(论文全文)》
《开源IM工程“蘑菇街TeamTalk”的现状:一场有始无终的开源秀》
《如约而至:微信自用的移动端IM网络层跨平台组件库Mars已正式开源》
《子d短信光鲜的背后:网易云信首席架构师分享亿级IM平台的技术实践》
《微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)》
《自已开发IM有那么难吗?手把手教你自撸一个Andriod版简易IM (有源码)》
《融云技术分享:解密融云IM产品的聊天消息ID生成策略》
《IM开发基础知识补课(六):数据库用NoSQL还是SQL?读这篇就够了!》
《适合新手:从零开发一个IM服务端(基于Netty,有完整源码)》
《拿起键盘就是干:跟我一起徒手开发一套分布式IM系统》
《适合新手:手把手教你用Go快速搭建高性能、可扩展的IM系统(有源码)》
《IM里“附近的人”功能实现原理是什么?如何高效率地实现它?》
《IM“扫一扫”功能很好做?看看微信“扫一扫识物”的完整技术实现》
《IM消息ID技术专题(一):微信的海量IM聊天消息序列号生成实践(算法原理篇)》
《IM消息ID技术专题(二):微信的海量IM聊天消息序列号生成实践(容灾方案篇)》
《IM消息ID技术专题(三):解密融云IM产品的聊天消息ID生成策略》
《IM消息ID技术专题(四):深度解密美团的分布式ID生成算法》
《IM消息ID技术专题(五):开源分布式ID生成器UidGenerator的技术实现》
《IM消息ID技术专题(六):深度解密滴滴的高性能ID生成器(Tinyid)》
《IM开发宝典:史上最全,微信各种功能参数和逻辑规则资料汇总》
《IM开发干货分享:我是如何解决大量离线消息导致客户端卡顿的》
《零基础IM开发入门(一):什么是IM系统?》
《零基础IM开发入门(二):什么是IM系统的实时性?》
《零基础IM开发入门(三):什么是IM系统的可靠性?》
《零基础IM开发入门(四):什么是IM系统的消息时序一致性?》
《IM开发干货分享:如何优雅的实现大量离线消息的可靠投递》
《IM开发干货分享:有赞移动端IM的组件化SDK架构设计实践》
《一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等》
《IM扫码登录技术专题(一):微信的扫码登录功能技术原理调试分析》
《IM扫码登录技术专题(二):市面主流的扫码登录技术原理调试分析》
《IM扫码登录技术专题(三):通俗易懂,IM扫码登录功能详细原理一篇就够》
《理解IM消息“可靠性”和“一致性”问题,以及解决方案探讨》
《阿里技术分享:闲鱼IM基于Flutter的移动端跨端改造实践》
>> 更多同类文章 ……
本文已同步发布于“即时通讯技术圈”公众号。
同步发布链接是:>
1、uni-app可以通过打包实现一套代码多端运行,而vue不行。
2、uni-app有自动的框架预载,加载页面的速度更快,vue没有。
3、uniapp使用小程序的标签,vue使用web端的标签。
4、uni不支持vue-router,使用自带的路由。
uni-app的优点
优点一:
uni-app是一套可以适用多端的开源框架,一套代码可以同时生成ios,Android,H5,微信小程序,支付宝小程序,百度小程序等。
优点二:
uni-app对前端开发人员比较友好,学习成本比较低,首先uni-app是基于vuejs的。其次封装的组件和微信小程序的组件一样。
优点三:
uni-app使用HBX进行开发,HBX对于vue语法等支持可以说是比较完备了。
uni-app支持的通用css单位包括px,rpx
vue页面支持普通H5单位,但在nvue里不支持;
nvue页面还不支持百分比单位
App端,在pagesjson里的titleNView或页面里写的plus api中涉及的单位,只支持px,此时不支持rpx。
nvue中,uni-app模式可以使用px,rpx表现与vue中一致,weex模式目前遵循weex的单位;
点击切换实现路由跳转
实现方法: 一、在indexvue的页面入口写一个点击方法,利用uninavigateTo({})写上将要跳转的页面路径。
二、 components文件里面创建headerNavvue组件
三、在pagesjson文件里写上组件路径进去
这里可以选择修改对应的样式信息
scroll-view属性说明:
横向滚动通过添加scroll-x="true",并且需要在scroll-view的上一级加上row,完成横向滚动
纵向滚动条通过添加scroll-y="true",并且使用scroll-view来配合完成纵向滚动轴
属性说明:
view的属性说明:
属性说明:
由于 icon 组件各端表现存在差异,可以通过使用字体图标的方式来弥补各端差异。
属性说明:
各平台type值的有效说明:
- 把一次请求拆分为多个任务,通过多进程或多线程的方式同时处理这些任务,充分利用计算机的资源
- 对比不同的配置和架构来提升性能,如使用CDN,静态缓存,缓存数据库查询等
- 合理调节服务器和数据库的配置
- 尽量减少数据库查询,使用缓存来提升数据库查询的性能
- 合理划分服务类型,将计算密集型和IO密集型任务分开处理
- 使用异步I/O模型来处理大量并发请求
18 年时候有幸接触到 uniapp , 写了一篇 《uni-app 入门到精通》 ,由于一些原因,该方案并没有执行,该项目一系列文章也就没有再写下去,所以遭受到了许多人评论的吐槽,到如今公司项目的需求又要根据 uniapp 写 H5 嵌入到 app 中,所以想根据项目实际开发分享一下,有兴趣的伙伴可以参考和吐槽。
这一篇文章主要分享一下内容
uniapp 模板项目有两种初始化方式
由于无法舍弃 VSCode ,我们采用 vue-cli 来初始化项目, HBuilderX 大家可以参照官方文档
这种方式是可以通过 vue 脚手架命令指定模板,这个是 dcloudio 的官方提供模板
我们选择默认模板即可,
成功后我们执行
打开浏览器地址,直接运行即可。
一般刚接触前端的小伙伴可能会对 postcss 不太了解,这里简单介绍一下,
当然 PostCSS 具体使用是需要引入一些插件的,例如常用的是 autoprefixer postcss-preset-env 等, 具体如何使用大家可以自行参考资料,毕竟这块知识还是挺多的就不具体展开解释了。
通常我们在写移动端时候需要做的是页面适配方案的确定, uni-app 支持的通用 css 单位包括 px、rpx , 之前的 upx 方案已经被废弃掉,官方解释是目前市面上已经基本上支持了微信的 rpx 方案,所以 upx 中转方案已经意义不大了,不过还可以继续使用,不过已经不再推荐。
rpx 之初是由微信小程序提出一种方案,即根据宽度来进行适配以 750 宽屏幕为基准, 750rpx 恰好为屏幕宽度, uni-app 规定屏幕基准宽度 750rpx 。所以说如果你们的UI 设计以 7501334 iphone 6/6s 为基准设计的话,你只需要将屏幕上 px 写为 rpx 即可,不用做任何换算,如果不是的话,你就需要做如下换算:
uniapp 有自己一套路由管理机制,而未采用 vue-route 方案,个人认为这套方案还是比较成熟和好用的,以及可以满足我们日常的需求:
保留当前页面,跳转到应用内的某个页面,使用uninavigateBack可以返回到原页面。
2uniredirectTo(OBJECT)
关闭当前页面,跳转到应用内的某个页面。
3unireLaunch(OBJECT)
关闭所有页面,打开到应用内的某个页面。
注意: 如果调用了 unipreloadPage(OBJECT)) 不会关闭,仅触发生命周期 onHide
4uniswitchTab(OBJECT)
跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。
注意: 如果调用了 unipreloadPage(OBJECT)不会关闭,仅触发生命周期 onHide
5uninavigateBack(OBJECT)
关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages() 获取当前的页面栈,决定需要返回几层。
5unipreloadPage(OBJECT)
预加载页面,是一种性能优化技术。被预载的页面,在打开时速度更快。
以上路由API 已经满足我们的需求,当然进行路由跳转的前提是我们需要在 pagesjson 进行路由配置, 包括路由和具体的样式配置
而进行具体路由跳转我们需要如下,需要多加一个 /
需要特别注意的一点是, 利用浏览器 在 进行 移动H5页面调试时候,会出现页面刷新之后页面栈会消失,此时navigateBack不能返回,如果一定要返回可以使用historyback()导航到浏览器的其他历史记录。
uniapp 提供网络请求的 api 是 unirequest ,具体支持的请求方法可以参考官网 method 有效值
不过我们通常不会直接使用,而是进过一系列的封装以方便我们的使用,具体封装接口使用会在随根据页面数据请求一并展示。
以上就是关于做混合的话Uniapp和Flutter我应该学哪个啊全部的内容,包括:做混合的话Uniapp和Flutter我应该学哪个啊、uniapp和vue有什么区别、Uni-App之Vue组件(三)等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)