作者简介
Brain,携程高级软件技术专家,关注前端技术框架、跨端技术方案、前端构建和工程化工具,致力于前沿技术和架构优化。
一、背景
FlightAI(市场洞察平台)是携程机票大数据团队推出的一款赋能行业的toB数据产品。FlightAI的用户群主要使用微信,但也有移动端和其他企业办公IM系统(如企业微信、钉钉等)的使用需求。由于大数据团队的前端工程师人数很少,且现有技术栈主要是web技术,缺乏移动端开发经验,因此需要选择一种以微信为主、研发成本低、跨平台(微信小程序、iOS、Android)应用的技术,以满足业务需求并提升研发效率。
FlightAI涉及大型表格操作与展示、大数据的图表绘制、大数据量数据指标呈现等场景,对查询和展示渲染性能要求较高。此外,还需要在微信公众号、web系统、小程序、移动端等多维度产品矩阵中实现业务功能、用户登录注册、账号管理与体系打通,形成立体式产品服务,以提升用户体验和运营效率。
1.1 难点与挑战
1.1.1 主要难点
a. 跨平台开发的复杂性:
- 虽然一些框架如React Native,Flutter,Weex等同构了iOS、Android的架构,但在独立完成移动端全流程开发和基础设施建设上,仍面临技术栈多样性的问题,特别是跨端架构中还需优先支持小程序。
- 需要掌握不同平台(iOS、Android、微信小程序)的证书管理、脚本命令调用、法律法规提示和约束差异、真机和模拟器开发、调试、构建、发布技术。
- 跨平台兼容性问题,如日历优化中遇到样式兼容性,性能问题等,需要深入理解各平台的差异和限制。
- 不同平台、不同流程下各种Token、认证和法律法规限制概念较多,较难分清。
- UI组件在各平台的兼容性、生命周期管理和权限系统、SDK稍有差异,一旦发生bug识别出这种差异较有难度。
b. 多端登录态打通:
- 需要解决不同平台间的登录态同步问题,确保用户在不同设备和平台上有一致的体验。
- 不同端的登录支持方式多样,需要做好同构和异构,如APP端需支持本机号码一键登录、账号登录、小程序登录、微信登录、苹果登录等,以支持各个平台的审核。
- Token种类非常多且复杂,各自用途不同,涉及前台与服务端code交换和token验证等逻辑。
c. 大数据列表渲染支持:
- 小程序双线程机制导致涉及交互的大数据列表渲染性能优化成为难题。
- 在小程序的技术架构下,官方支持最大DOM数是16000个,text类节点也被计算在总节点数中,容易超过DOM数限制,导致"Dom limit exceeded"错误。
1.1.2 新技术平台的挑战
a. 功能覆盖率:
- 虽然官方号称跨多端,但功能覆盖率、API覆盖率是否足够,接入是否复杂,能否满足当前和未来的需求?
b. 基础设施:
- 研发工具、测试工具、部署工具、运维工具是否成熟,遇到问题如何快速找到支持和解决方案?
c. 研发生态兼容性:
- 除了大的跨端技术框架面临挑战,落地实施会面临更多小型技术选型的挑战,如组件系统、图表库、其他平台支持、兼容性问题。
1.2 技术选型
1.2.1 业务需求与现状
a. 团队规模小,跨多端需求和高研发效率需求:
- 小型研发团队,现有技术技能主要是JS技术栈,缺乏移动端开发经验,必须控制培训成本和研发成本;
- 考虑集成难度和行业趋势,分析功能需求和性能需求等,FlightAI用户有强烈的移动端使用需求,仅开发小程序无法满足;
- 需要选择一款技术复杂度低、研发成本低、技术栈简单的跨平台框架,而Donut技术满足跨多端、高性能、低成本需求,且有腾讯官方支持;
b. 业务需求:
- 建立独立账号体系、独立域名和品牌,要求与微信公众号、web系统体系化运营,形成产品矩阵;
- 微信小程序在功能和性能上都要求高优先级支持;
c. 高性能需求:
- Donut在小程序支持度和App性能上表现优异。在App上底层基于Flutter,使用和微信小程序相同的一套容器,接近原生渲染性能;
- FlightAI具有大批量数据实时渲染的需求,对渲染性能要求很高;与公司框架计划支持使用Flutter提升渲染性能的技术路线一致;
1.2.2 为何选型Donut技术
由于用户群体主要以微信小程序为主要使用场景,所以无法支持小程序的多端框架如React Native,Flutter等无法选用,而既支持小程序又支持移动端的技术框架,目前市面比较流行的是taro和uni-app,但存在如下顾虑:
- 使用该类框架后,功能更新完全依赖于框架,微信小程序里有的功能可能无法支持;
- 使用该类框架后,代码经过二次转换,性能可能不如原生WXML,而且会带入转换逻辑额外引入的代码和性能忧虑;
- 该类框架一般都会自定义DSL,有一定的学习成本,文档是否健全,社区支持是否完善将直接影响配置和自定义功能的效率;
- 该类框架优势多在跨多端小程序,实际上线APP的案例并不多,大坑小坑无法避免,例如uniapp的nvue原生开发有局限性,特别是样式方面限制比较严重;
- 跨多端应用开发的全生命周期集成和管理能力是否强大,包括开发,测试,构建,发布,运维,法律法规提示与解读,token管理等;
而Donut是腾讯官方推出的和小程序同源容器,在功能和性能上比这类衍生框架更优秀,在App上底层基于Flutter,接近原生渲染性能;Donut以小程序DSL作为开发语言,可以无缝切换,也没有二次转换的成本,会开发小程序就会写Donut APP。在研发工具、测试工具、部署工具、运维工具上腾讯做了全方位集成,小型团队可能遇到的问题几乎全部涵盖。官方文档一步一截图,阅读体验良好,总结如下:
a. 功能覆盖率较高
常用需要适配API(8个),根据使用情况进行选择支持,Donut官方提供了非常多的功能API,从功能支持度、易用性和架构上App小程序同构上也可以看出官方的大力投入。
JSAPI 和组件支持汇总,涉及6大方面
组件部分:视图组建,表单,导航,媒体,地图,画布,开发能力,原生组建都能较好支持;
API部分支持情况:总共大概507个API;支持371个,大概占73%,部分支持或者不支持的部分官方提供一些其他的替代方案;(2024-03统计)
SDK部分:基础SDK和扩展SDK支持较好;这部分是Native功能,根据需要进行勾选,不选就不会打入包中,按需打包降低包size;
NativePlugin:支持Native自定义扩展,该部分都是一次性工作,除非有强烈的自定义需求,一般都用不上;
云支持:云开发云托管,Donut网关防护;
埋点监控:热力图,回放功能支持完善,支持全埋点;
b.基础设施较完善
Donut 平台覆盖开发、部署、产品体验分析全产品开发周期的各种需求,研发工具、测试工具、部署工具、运维工具上腾讯做了全方位集成,基础设施比较完善,贯穿产研全流程支持,可大幅提升研发效率,特别对于没有移动端研发经验的团队具有引导和指导的作用。
- 多端框架-支持使用小程序原生语法进行一次代码编写,多端编译,实现多端开发。
- 多端身份管理-几行代码,快速实现 App、小程序的身份认证和用户管理。
- 安全网关-提供弱网加速、防爬防刷、流量治理等能力,全方位保障业务安全高效稳定运行。
- 产品体验分析-从真实的用户视角洞察产品问题,寻找产品体验的不足之处,提升用户留存与转化,具有如下功能:
- 零代码、全埋点
无需开发,一键接入,元素自动全埋点,快速开始小程序数据分析。 - 还原用户操作现场
创新可视化日志 & 热力图,还原用户实际操作现场,问题分析一目了然。 - 可视化交互分析
全程无需 SQL 编写,仅需在模拟器上点选交互即可完成分析过程。 - 一键智能分析
无需数据分析背景,根据业务目标智能分析,查找用户漏点,提升转化率。
c. 研发生态兼容性较强
- UI组件系统
UI组件系统选型TDesign还是使用WeUI,还是使用Ant Design for Mobile,NutUI,Vant,Material-UI?
主要考虑组件的成熟度,兼容性,组件功能,TDesign是腾讯官方出品的组件库,而WeUI则侧重提供样式库,考虑社区实践经验,最终选择TDesign,组件相对丰富,常用组件齐全,贴合微信设计规范,在Donut APP的兼容性较好,复用组件可以节省不少开发工作量。
- 图表库选择
图表库使用echart还是g2移动版图表库,还是选择wx-chart,ucharts,D3,antV,Threejs等图表库?从如下几个方面进行了考虑:代码规范:EChart、D3官网的部分案例还是使用了ES5的语法,Antd遵循了ES6新语法规范。灵活度:ECharts<G2<D3;使用难度:Echart≈G2PLot<G2<D3;场景:三维图推荐用Threejs,二维图用ECharts或者G2、G2Plot均可;考虑到FlightAI图表类型为常规图形,而且PC版本选型也是Echart,在小程序集成和兼容性上,Echart都表现较好,但Echart在分辨率处理上和Donut系统并不兼容,但在编写适配层解决该难题后,用起来非常丝滑,所以最终选定Echart。
- 小程序兼容性
小程序转其他小程序或者web的方案调研如morjs等转出来的小程序,其他跨多端如Taro转Donut技术是否可行?
理论上Donut提供的是小程序运行容器,其他跨端或者转换技术只要最终产物符合微信小程序规范,应该可以运行,但是转换必然导致功能和性能上有损耗,而且对于Donut条件编译等语法需要进行特殊处理,一般转换代码会带来额外的处理逻辑,会增大包Size,虽然有副作用,但Donut本身的扩展能力还是很强的,毕竟提供了和微信一致的小程序容器。
1.3 Donut简介
Donut平台是腾讯出品的基于小程序实现跨多端(小程序,IOS,Andord)的技术体系,覆盖了开发、部署、产品体验分析全产品开发周期的各种需求。开发者可以专注于代码逻辑,将复杂的开发构建流程,开发及运行环境等统一管理,有效降低多端应用开发的技术门槛和研发成本,以及提升开发效率和开发体验。包含4大特色能力:多端框架,多端身份管理,安全网关,产品体验分析。
1.3.1 Donut系统模块图:
主要分为客户端和云端功能,客户端主要负责端侧的标注化容器,处理小程序基础库,小程序SDK等基础设施,云侧主要处理各种管理和审核功能,流程都集成在了微信开放平台,微信开发者平台,微信公众平台,Donut管理平台几大平台上。
1.3.2 Donut工作流程
简单理解,就是微信抽象了一个简化版本的微信APP作为容器,底层都是基于Flutter进行渲染,承接小程序的能力,并利用微信开发者工具提供研发支持;理论上只要是微信小程序都能运行在该平台上。
1.3.3 Donut技术适合谁
a. 基于小程序生态开展业务的个人或企业;
b. 需要跨多端支持、高性能和高研发效率的项目;
c. 已经拥有小程序,想扩展到移动端的项目;
d. 希望简化或标准化开发运营流程,利用微信提供的全软件研发周期集成能力的项目。
二、FlightAI如何基于小程序构建一款跨多端移动应用Donut-APP
首先在微信公众平台(mp.weixin.qq.com)注册小程序,完成注册后可同步进行信息完善和开发。下载微信开发者工具、参考开发文档进行开发和调试。要成为Donut跨多端研发人员需要了解如下信息:
2.1 多端应用开发:开发账号准备
2.2 了解账号关系
2.3 多端应用开发:开发资源准备
2.4 开启多端应用模式
a. 新建或者升级小程序为多端项目即可
b. Donut多端项目结构
和小程序项目结构一致,只是多了一些跨多端框架的配置文件,app.miniapp.json主要作用是维护多端应用和小程序绑定关系,配置App小程序登录页面地址,授权页等。
project.miniapp.json则主要用于配制原生插件,多和native交互有关;project.config.json则是小程序相关的配置文件。
2.5 了解条件编译
Donut支持以条件编译的方式编写特定平台代码;如有些组件只有微信支持,有些业务需求只在微信展示,那么就需要条件编译实现差别需求,在app上和小程序使用不同的代码方式实现,一般该类代码占比较少,FlightAI项目中,我实现了自动统计条件编译代码的功能,可统计上报或者单机运行了解项目状态。
2.6 多种登录方式支持-多端身份管理
a.FlightAI登录架构设计
Donut支持多种登录方式,一般项目完全够用了,并在后台做了较好的集成管理,官方叫做多端身份管理,FlightAI的场景比较复杂,除了Donut提供的5登录方式之外,还支持了密码登录等总共10种登录方式,给客户最大的便利和可选择性;支持方式多样,但是底层验权,鉴权,授权等接口都实现了统一。
b.小程序和 App 的统一身份识别
小程序的token和code2Session接口进行交换,App的token和code2Verifyinfo接口进行交换,各个接口都有配套API,比较复杂,不能搞混了,最好单独一整套接完,再接入另外一套。
2.7 大列表渲染
在webview的双线程架构下,小程序的官方支持最大Dom数是16000个,text类节点也被计算在总节点数中,非常容易就超过Dom数限制,导致Dom limit exceeded, please check if there's any mistake you've made.
无论是模拟器还是真机,小程序还是Donut APP,在FlightAI场景中view-all页面,经过测试442条渲染Item是临界点,超过442条就会白屏,在该数据结构下Dom数会达到临界点,并且442条数据在IOS模拟器上渲染耗时5646ms,这也侧面证实了各端各工具在Dom数限制上是一致的。
官方推荐标准
官方推荐说明(也是评分标准),单页面节点尽量不超过1000个节点,嵌套不超过30层,子节点不超过60个,页面深度不超过10个;但功能较为复杂的页面,非常容易就超出限制,那么如何突破这个问题呢?
长列表渲染特点
1)列表数据很大,首次 setData 的时候耗时高,双线程模型使得交互性能成为瓶颈;
2)一次渲染出来的列表 DOM 结点多,每次 setData 都需要创建新的虚拟树、和旧树 diff 操作耗时都比较高;
3)渲染出来的列表 DOM 结点总数多,占用的内存高,造成页面被系统回收的概率变大。
优化思路
要么彻底改变双线程的底层架构,要么通过一些手段优化参与渲染的数据和状态,只渲染显示在屏幕的数据,基本实现就是监听 scroll 事件,并且重新计算需要渲染的数据,不需要渲染的数据留一个空的 div 占位元素。如下是2个解决方案:
a.微信官方提供recycle-view的解决方案,虚拟列表方案;
在滚动过程中,重新渲染数据的同时,需要设置当前数据的前后的 div 占位元素高度,同时是指在同一个渲染周期内。页面渲染是通过 setData 触发的,列表数据和 div 占位高度在2个组件内进行 setData 的,为了把这2个 setData 放在同一个渲染周期,用了一个 hack 方法,所以定义 recycle-view 的 batch 属性固定为 batch="{{batchSetRecycleData}}"。
b.微信官方为提升渲染速度,开发了skyline渲染引擎。
skyline渲染引擎,使用更精简高效的渲染管线,并带来诸多增强特性,让 Skyline 拥有更接近原生渲染的性能体验。
使用skyline之后,不会有dom数限制了;而且很明显的一个对比是使用skyline后,快速滑动长列表不卡顿,首页没有开启skyline快速滑动会卡顿。
注意列表布局容器,仅支持作为 scroll-view 自定义模式下的直接子节点或组件直接子节点,scroll-view要设置自定义模式 type="custom",list-view要作为 scroll-view 直接子节点。
WebView 的 JS 逻辑、DOM 树创建、CSS 解析、样式计算、Layout、Paint (Composite) 都发生在同一线程,在 WebView 上执行过多的 JS 逻辑可能阻塞渲染,导致界面卡顿。
Skyline 创建了一条渲染线程来负责 Layout, Paint 和 Composite等渲染任务,并在 AppService 中划出一个独立的上下文,来运行之前 WebView 承担的 JS 逻辑、DOM 树创建等逻辑,架构深度优化后性能提升显著。
Skyline长列表官方文档
性能对比
官方示例:小程序助手的线上数据,可以看出 Skyline 的首屏时间比 WebView 快 66%,并且手机性能越低端,差异就越明显。
另外尝试自行计算小程序的Dom数,Dom层级,做统计或者优化,发现querySeletorAll API无法使用通配符,另外涉及到Shadow-Dom,计算变得非常麻烦;向微信官方求证过Dom最大size的数量是16000个,这是编译器层面的限制,无法放开。经过和微信官方沟通结果是他们可以提供小程序的Dom数计算API,目前还没有提供,将来可以提供。
2.8 实现Push消息推送
FlightAI接入TPNS或者公司的Push系统的一些思考和调研;腾讯云有提供TPNS,但是这套推送接入成本较高,而且已停止售卖;收费标准大概是800*DAU/10000,8分钱/条,按用户收费。
Donut提供了基于IM的新版本推送服务,2024-8月份开始支持;通过配置插件和证书实现推送功能,支持在线推送和离线推送;IOS和Android的各个厂商需要分别进行配置,这是厂商的规范不同导致。
新版本收费规则根据数据中心位置和不同的套餐有所不同。后台需要根据各厂商申请对应的证书AppKey和AppID,并根据需求制定推送策略。
对于接入成本的考虑,在客户端只需简单配置PluginId即可,配置示例:
2.9 正式构建APK和IPA
构建移动端APP的临时签名和正式签名是区分的,临时签名Donut官方直接提供,正式签名证书,需要研发人员按照目标平台进行注册,上传,注意签名文件对目录有要求,必须放在项目内,IOS的钥匙串必须和配置中的名称完全一致。
2.10 内测分发与提交审核
在开发者工具上 选择 正式版点击「构建」- 「上传资源包」,即可将开发版本的资源包上传至Donut资源包管理平台,之后跟进研发流程自行决定测试版本和线上版本。
2.11 完成各平台隐私协议,法律条款,授权弹窗等上架要求,发布APP
需要注意的是各大电子市场的要求各不相同,为了能够上架,需要满足各平台的各种规范,否则审核无法通过,特别是涉及法律条款需要法务部门介入,通常时间非常长,要做好相关准备。
2.12 踩了哪些坑
- 一些证书导致的问题
在进行基础设施建设中,完成小程序,Donut跨多端基建,包括环境搭建、系统配置、开发、测试和发布流程的打通, 技术框架搭建,架构设计模型,开发流水线等。比如证书位置不对,证书信息不匹配,申请证书的Domain,link等信息不一致,在构建的时候可能会报一些奇怪的错误,始终无法通过构建,这块的研发信息提示很不明确,但会Block研发进程,已建议官方优化; - 构建产物,虽然功能增多,业务逻辑变的越来越复杂,包size会正常增长,但是如果有自定义管理资源包的需求,那么就会遇到包size上传限制的问题,那么就需要分包,比如我们nephle最大支持30M的包,需要解决分块上传问题;另外如果要实现ios自动下载安装的能力,模版地址和包地址需要放在同一目录,否则坑较深,会浪费不少精力和时间;另外真机调试和构建,直连的数据线非常重要,带转换的多功能数据线很有可能带来不少意外的构建问题;
- 功能开发与性能优化:图表功能开发,日历功能开发与性能优化,TDesign官方日历组件存在性能问题,官方提供的format钩子,在遇到多年份日期遍历的时候,性能问题突出,t-calendar并且不支持虚拟列表,所以性能不理想,采用Hash算法后优化了近400倍,提升日历功能的性能,另外TDesign和Donut是不同的团队,提issue的时候要找准团队,否则可能不被受理。
- 小程序备案,域名备案,微信认证,用户告知,服务条款,隐私协议,软著商标,何时启动?有哪些坑?
法务审核和各种认证需要准备很多企业实体资料,尽早准备提交,完全按照文档操作,否则会被打回重写,再者审核周期不可控,应当尽早启动,隐私弹窗和授权弹窗必须使用模版或者native开发,不能使用其他方式,因为APP在授权之前是不能加载和运行代码的。请仔细阅读相关章节注意事项; - token管理
token是测试一套,生产一套,配置不同,Android和IOS平台各自管理一套,另外mobileprovision必须包含Doman,而且Donut和开发工具,APP中的信息必须一致;
三、成果与经验
3.1 技术创新与效率提升,代码复用率99%
- 代码复用率:实现了99%的代码复用率,特定平台代码代码为非复用代码,自行实现了自动统计的功能;
- 成功研发一款跨平台高性能APP:成功开发了业务代码基于小程序,底层框架与微信同源基于Flutter的高性能跨多端移动应用,确保iOS、Android和微信小程序上的一致性和高性能,为公司探索新跨多端技术方案;搭建了iOS和Android应用的自动化构建和持续集成(CI/CD)管道,提升了开发和发布效率;
- 采用Skyline新渲染引擎, 首屏时间比 WebView 快 66%,更重要的是Skyline没有Dom数限制,对于开发大型项目来说非常重要;
- 一码多端,跨多端真机效果;
3.2 打造产品矩阵,用户体验
为了提升携程市场洞察平台的应用范围和市场竞争力,我们打造了一个全面的产品使用矩阵,实现了移动端、小程序、现有的Web端、微信公众号和API服务的完整覆盖。通过这种多端覆盖,我们能够更好地满足用户在不同场景下的使用需求,提升产品的市场竞争力。
为了提升用户体验,我们打通了多种设备和多种类型的登录态,支持用户通过不同设备和渠道无缝登录。除了Donut提供的5登录方式之外,还支持了密码登录等总共10种登录方式,给客户最大的便利和可选择性。
在市场洞察平台中基于Donut实现了跨多端高性能移动端的技术实践,确保了产品在各种移动场景下的优异表现。
通过这些技术创新和优化,我们不仅提升了产品的应用范围和市场竞争力,还显著改善了用户体验,为用户提供了更加便捷和高效的使用体验。