点击围观!腾讯 TAPD 助力金融行业研发提效、敏捷转型最佳实践! 了解详情
写点什么

有赞移动消息卡片动态化方案实践

  • 2020-08-08
  • 本文字数:3473 字

    阅读完需:约 11 分钟

有赞移动消息卡片动态化方案实践

概述

消息业务作为有赞移动的共享业务,在微商城、零售、美业等 B 端 App 中承担着多客服的角色,多客服是有赞为商家提供的连接商家和买家的即时消息客服工具;在精选、有赞客 C 端产品中扮演着用户联系商家的角色。在整个有赞产品中,是商家和用户沟通的桥梁,起着非常重要的作用。

痛点

我们通常来讲把出现在消息会话页面内的内容称做消息卡片,目前消息业务常见的消息卡片有文字、富文本、语音、照片、视频、通知消息,除此之外还有订单详情、推荐商品、核对订单等共计 30 余种消息卡片。目前我们消息卡片都是采用原生来开发,随着业务的日益增多,消息卡片的数量也在成倍的增长,业务方经常提出增加卡片的需求,去开发和维护这些卡片工作量比较大,并且依赖业务方的客户端发版,不够灵活。

现状

目前消息业务在 iOS 端和 Android 端均采用二方库的方式开发,供各个有赞的 App 接入,在 iOS 中采用 Cocoapods 进行二方库的依赖,Android 采用 gradle 来进行二方库的依赖;如果业务方需要增加一种消息卡片从开发到上线按照正常的周期是 1 周到 1 周半,发版周期长、开发效率低。


动态化技术指不依赖 APP 发版,就能进行动态的增加或者修改来更新页面的技术。对于消息卡片这种需要快速迭代、实时调整的业务,动态化具有非常重要的意义。主要优势体现在:


  • 提高人效

  • 缩短版本迭代试错周期

  • 解决版本长尾问题

  • 减少包大小等


整个消息的业务场景如下图所示:



消息聊天以及消息模版都是由消息卡片组成

原生消息卡片

先来说说原生消息卡片的实现方案,这里以 iOS 为例。整体架构设计我们采用 TableView 作为整个页面的容器,采用 MVVM 的架构去设计,架构分为以下模块:


  • 消息卡片数据源配置类 Configurator 负责 VC 和数据源处理类的绑定以及消息管理处理

  • 消息卡片接口管理类负责接收/发送消息数据处理,重发的操作、界面接口(增、删、改、查)

  • 数据源操作类 TableAdapter 负责 TabelView 的代理方式、数据源代理方法的实现,以及一些视图刷新等相关操作

  • 消息卡片内容视图工厂类 ContentFactory 会根据消息类型注册对应的 ContentConfig 进行一个缓存

  • 消息卡片配置类 ContentConfig 是根据消息类型从工厂类中获取的,返回当前消息卡片的宽高(size)、消息体 message、当前渲染的消息卡片视图

  • 消息模型 layout ,根据不同的消息类型生成,会保存当前的消息体以及消息卡片的宽高,为了提升性能,缓存在 TableAdapter 数据源操作类中

  • 消息卡片 cell,根据后端下发不同的卡片类型,从消息卡片配置类中获取不同的 contentView 加到 cell 中,进行消息卡片的展示

  • 消息卡片 contentView,负责消息卡片 UI 布局、数据的渲染、绑定


整个架构如下图所示:



消息原生架构图

方案

关于动态化技术栈的选择

上面介绍了 iOS 端消息卡片渲染架构设计,那么为了让消息卡片具有动态化的能力,但是不会打乱现有原生架构的情况下,我们采用了结合 weex 技术栈来做这件事。为什么用 weex 来提供动态化这样的能力?首先该技术栈已经在有赞移动中扮演者重要的角色,我们团队之前已经做了 weex 无线开发平台,我们团队主导建设了 ZanWeex ,它是一整套解决方案,从开发、构建到发布、热修、数据、监控,全生命周期的平台和工具,目前有赞业务很多模块都是以 weex 来实现,也接入了长连接功能,无须重启 App 实现实时下发的功能,对 weex 有兴趣 的,可以查阅 weex 官网。


因此我们的核心思路是利用 weex 来达到消息动态化的目的。


  • 创建 weex 容器,为了避免容器臃肿, 这里我们没有选择 ViewController 来充当 weex 的容器,而是用 View 来充当容器,里面包裹了一个 WXSDKInstance 进行 weex 的渲染。

  • 原生端创建渲染 weex 的 TableViewCell,将 weex 容器视图添加到 cell 的 contentView 中去,利用 TableView 的重用机制进行 cell 的缓存和重用。

动态化能力

技术架构设计

在架构设计上面,我们在以前原生的 MVVM 的基础上,利用 JS 动态库,配合 weex 达到动态化卡片的能力,做到了 App 不发版的情况下,只需发布 weex 就可以动态添加消息卡片,也可以修改消息卡片的 UI 样式。鉴于这样的设计目标,在这个框架里,主要考虑以下方面:


  • 在不改变原有原生架构的基础上去做消息卡片动态化

  • 页面布局动态化,意思是页面的排版布局,可以通过 weex 端和 JS 端发布来达到动态更新

  • 组件的复用,为了在多种类型的卡片中保持良好的性能,需要对 weex 端容器进行缓存和复用

  • 开发、构建、发布整个流程需要拥有一个完善的平台

JS 动态库

JS 动态库是我们团队出的一个动态化方案的框架,主要功能是提供动态下发的能力;快速修复线上问题;两端特殊复杂的逻辑保持一致等。JS 动态库也是利用 ZanWeex 平台来开发、构建到发布,一整套流程都是完善的,这里我们不去过多的讨论 JS 动态库的相关内容,我们仅仅是用到动态下发的能力,核心思路是:


  • 利用 JS 动态库根据消息类型下发对应的 weex 卡片的 url

  • 利用 JS 动态库根据消息内容和消息类型来计算原生承载 weex 容器的 TableView 的 cell 宽高

  • 利用 JS 动态库下发需要加载 weex 卡片的消息类型

  • 利用 JS 动态库根据消息类型来判断当前的 cell 是否是 weex 卡片 cell

接入 JS 动态库

  • 我们在 JS 动态库中,暴露出获取 weex 卡片对应的 url 方法,入参是消息类型

  • 获取 weex 卡片所在的 cell 的宽高,入参是消息卡片内容和消息类型,JS 将卡片内容解析出来,进行高度、宽度的计算返回给原生。

  • 获取需要支持 weex 卡片的消息类型,原生根据这些类型进行容器 cell 的注册

性能

性能较好,在多个 weex 卡片消息交替出现的时候,为了避免达到性能瓶颈,因此首先考虑到利用原生 TableView / RecyclerView 的重用机制,拿 iOS 来举例,用 weex 的 url 和 TableView 的 identifier 做一个绑定,这样不必自己去维护 weex 卡片的重用和回收。第一版做出来的时候发现,这样在持续加载 weex 卡片的时候 WXSDKInstance 会不停的渲染调用 renderWithURL 方法,这样无疑是消耗比较大的性能去创建 weex 视图。因此我们在 weex 容器中做一个标记,记录上次该容器加载的 url,每次在加载 weex 卡片 cell 的时候去判断当前的 url 是否是上次记录的 url,如果是,就说明这个类型的 weex 卡片之前已经渲染过,WXSDKInstance 实例可以拿到原生传过来的数据进行 refreshInstance;否的话用 WXSDKInstance 进行 renderWithURL,这样可以节省一次 render 重新渲染,从而解决卡片太多,上下滑动的时候会出现短暂的空白现象。

整体流程

  • 消息通道连接的时候,weex 模块去拉取对应的注册的 weex 页面;初始化 JS 动态库,其实也就是拉取 JS 相关的逻辑配置

  • 后端下发消息数据,经过数据解析器将消息经过转化生成 layoutModel 缓存起来

  • 在消息卡片视图工厂类 contentFactory 中,将消息类型传到 JS 端来判断当前消息类型是否需要注册成 weex 卡片

  • 在获取卡片宽高、消息模型的卡片内容配置类 contentConfig 中,将消息类型、消息内容传到 JS 端,返回 weex 卡片宽高

  • 数据操作类去持有 LayoutModel 和 contentConfig 类,在 TableView 代理方法回调的时候,去加载对应的 weex 卡片和宽高,并且将 weex 卡片的 url 作为 identifier 重用标记

  • TableView 加载 weex 容器的 Cell 时传递消息类型到 JS 动态库,然后返回对应的 weex 卡片 url,然后根据 url 将消息卡片内容传递到 weex 容器端去进行渲染或者刷新


架构设计如下图所示:



消息动态化架构图

优化

目前整个流程已经上线,情况比较稳定,极大的提高了开发效率,增加/修改消息卡片做到完全动态化,但是目前我们的方案也有很多不足之处,比如我们期望更好的性能和更高的运行效率、更加动态化的事件处理能力、更加方便的开发体验,对此我们也做了更进一步的规划建设:


  • 组件创建、布局计算、数据绑定机制、从 JS 端获取数据做缓存的优化,提升性能

  • 规范事件点击回调处理,提供跳转商品详情、订单详情、原生特定页面 router 以及 webView 的事件处理

  • 拆分出动态化框架 SDK ,让其他需要用到的业务可以接入,比如一些活动页面

总结

以上是我们整个消息卡片动态化的整体方案,总结来讲就是在原生架构基础上配合 weex 技术栈、JS 动态下发,达到整个动态化的目的,可以算作一个轻量化的动态化方案,算是在动态化方面做一些尝试,也希望可以和广大开发同学一起交流。


参考链接:



本文转载自公众号有赞 coder(ID:youzan_coder)。


原文链接


https://mp.weixin.qq.com/s?__biz=MzAxOTY5MDMxNA==&mid=2455761163&idx=1&sn=32e318bdf0c847021abc5e621193172c&chksm=8c68772ebb1ffe38768f187645f73848879ed6bd7baf8f50a4b6e81556dc8b7ab56868d22579&scene=27#wechat_redirect


2020-08-08 14:052408

评论

发布
暂无评论
发现更多内容

一文带你认识CSS

未见花闻

6月月更

python程序设计思想

左手の明天

Python 面向对象

考试试卷存储方案

极客土豆

InfoQ 极客传媒 15 周年庆征文|海王的鱼塘是怎样炼成的

知心宝贝

人工智能 大数据 运维 前端 InfoQ极客传媒15周年庆

关于微服务通信的一些Tips

阿泽🧸

微服务 6月月更

Navicat Premium 15 永久破解激活工具及安装教程(亲测可用)

Geek甜甜

数据库 程序员 工具 navicat

力扣每日一练之二维数组下篇Day5

京与旧铺

6月月更

在 Pisa-Proxy 中,如何利用 Rust 实现 MySQL 代理

SphereEx

MySQL 数据库 rust

LabVIEW Arduino ZigBee无线气象站(项目篇—3)

不脱发的程序猿

物联网 LabVIEW Arduino ZigBee无线气象站 无线传感器

SeekTiger迎多重利好,旗下生态NFT、DAO VC平台将陆续上线

威廉META

Java Core 「10」J.U.C 同步工具类-2

Samson

学习笔记 Java core 6月月更

Android 自定义View之展开收起的Layout

yechaoa

android 自定义view 6月月更

跟着官方文档学 Python 之:3.12 新变化

甜甜的白桃

Python python3.x 6月月更

配置swagger

卢卡多多

swagger 6月月更

LabVIEW Arduino无线蓝牙遥控智能车(项目篇—2)

不脱发的程序猿

LabVIEW Arduino VISA 无线遥控智能小车 无线蓝牙遥控智能车

依图在实时音视频中语音处理的挑战丨RTC Dev Meetup

声网

音视频 RTC Dev Meetup 语音处理

如何设计BI平台

奔向架构师

数据仓库 商业智能 6月月更

flutter系列之:深入理解布局的基础constraints

程序那些事

flutter 程序那些事 6月月更

「 2022 精益软件工程大会」圆满闭幕,观测云奉献精彩主题演讲

观测云

JASON

Jason199

json js math 6月月更

5分钟了解红队如何搜索网络情报

穿过生命散发芬芳

6月月更 攻防演练

【愚公系列】2022年06月 通用职责分配原则(五)-控制器原则

愚公搬代码

6月月更

Docker 实用技巧二

Nick

Docker 容器 实用技巧 6月月更 实操

JVM调优简要思想及简单案例-代码执行与内存区域

zarmnosaj

6月月更

百度团队CSS编码规范

yinhaixiang

数据库每日一题---第15天:未消费的顾客

知心宝贝

数据库 程序员 前端 后端 6月月更

倒计时1天,龙蜥社区走进Intel MeetUp 即将开播!直播大奖等你来拿

OpenAnolis小助手

开源 intel Meetup 龙蜥社区 线上直播

Java—JVM

武师叔

6月月更

leetcode 413. Arithmetic Slices 等差数列划分

okokabcd

LeetCode 算法与数据结构

如何往 Kafka 发送大消息?

Se7en

有赞移动消息卡片动态化方案实践_移动_杨彬_InfoQ精选文章