MCube动态化与原生工程结合最佳实践 | 京东云技术团队

京东云开发者
• 阅读 281

跨端动态化开发方案重要性日益凸显,本文对我们团队MCube动态化实践做了总结,为大家提供经验和借鉴。

接入背景

随着我们工程的需求迭代,暴露出了业务需求量大,分端开发和发版更新成本高等痛点,使用H5页面来代替,在用户体验和性能相较原生有差异,所以我们团队开始了对动态化改造的研究。

在做过一些列动态化开发的尝试,并对多种方案进行调研后,我们选择了MCube的动态化方案。之所以选用MCube,是因为它有以下的优点:

1.方案成熟,对同为京东体系下的APP来说接入成本非常低,对照文档文档,整个接入的过程并不复杂。2.MCube有丰富原子组件,组件的灵活性非常高。

3.完善的组件市场可以很好的满足我们的需求。

4.一套XML模板适用多个平台,并且可以复用。

我们在接入的过程当中遇到兼容性问题,在沟通过程中,MCube的负责同学和开发人员积极性非常高,定制化开发的效率也很高,认真负责,有问必答,整个沟通过程非常愉快。

我们团队目前已经完成了从初步尝试,到一整个业务页面动态化改造的完整历程。期间遇到了许多问题,总结出了最佳化实践的经验,本篇文章做出总结,为其他已经接入和准备接入的同学提供经验。

单楼层动态化改造

虽然MCube的SDK提供了丰富的接口方法,但是为了方便使用和后续的全页面级别动态化控制,我们还是做了大量的封装和本地化开发。

首先,在数据层面:

MCube动态化与原生工程结合最佳实践 | 京东云技术团队

根据MCube SDK的必传参数要求,我们封装了必要的module(页面名)和templateID(模版ID);在数据部分,模型封装了用于模版的数据源data,这样就可以让动态化视图(DYNContainerView)从数据源取数据进行展示,同时也方便外部下发;同时我们有大量原生楼层做动态化改造的场景,需要保留原数据进行交互和降级,所以模型预留了原生楼层使用的nativeData,方便在有以上需求的时候取用;最后,考虑到页面有将某些楼层按照section成组进行展示的场景,模型设计了用于组划分的groupID,相同groupID为一个section,按照页面具体的业务需求决定组的展示形式(卡片或者分割)。

在视图层面,以封装好的DynamicViewModel为基础,将动态化视图加载等操作进行了封装,形成了通用楼层CommonTableViewCell:

MCube动态化与原生工程结合最佳实践 | 京东云技术团队

通用楼层的能力包括:

1.解析module和templateID

2.调用MCube SDK下载对应动态化模版,并在结束时给出回调

3.展示动态化视图DynView,使用数据进行刷新

4.支持设置降级视图,失败时进行降级

5.对于元素是原生视图的,通用楼层会用过layoutId将其找到,并通过Block回调出来,方便进行后续的操作,包括宽高调整,代理设置等等

self.successBlock = ^(DYNContainerView * _Nonnull dynamicView) {
    UIView *nativeView = [dynamicView getRrenderViewWithLayoutId:@"100"];
    if ([nativeView isKindOfClass:[原生视图类名 class]]) {
       //原生事件处理   
    }
};

全页面动态化改造

有了通用楼层,我们就开始了下一步的改造,最终的目的是实现全页面动态化下发,这也是我们团队对于动态化改造的新理解:全页面的所有楼层均支持动态化下发,原生楼层与动态化楼层共存,由数据来驱动,灵活控制楼层的展示形式,另外还可以由配置平台设置开关,控制动态化楼层的降级。

理想情况下,业务页面的顺序和楼层数据都可以由后端下发的数据源来决定。但实际进行改造的时候,我们时常会面对的情况是:后端下发的result里混杂着所有楼层的数据字段,每个楼层在加载数据model的时候要到result里单独找到自己要用的字段进行解析,这样就存在着两个弊端:

1.楼层顺序无法由下发控制

2.无法做到分楼层动态化控制

所以我们改造的第一步是对下发的数据结构进行重新定义。

"result":{
    "dynamicFloors":
        [
            {
                "type":"楼层类型",
                "module":"页面名",
                "templateID":"模版ID",
                "groupID":"part1"
                "data":{
                }
            }
        ]
}

我们设定了一个动态化楼层数组dynamicFloors,里面的每个元素代表了某一楼层的数据。type用于确定楼层类型,对于动态化楼层,会额外下发module和templateID,以此来区分动态化和原生楼层。如果发现下发了module和templateID,那么自动用DynamicViewModel来解析,将data设置进数据源,然后用CommonTableViewCell来加载和展示楼层。流程图如下:

MCube动态化与原生工程结合最佳实践 | 京东云技术团队

后续可以推动服务端按照这个结构进行下发,当然,在推动其他团队同学改在之前,前端也可以先行对下发的result进行改造,但千万要保证数据安全并做好容错处理和降级开关。

改造成果:

MCube动态化与原生工程结合最佳实践 | 京东云技术团队

踩坑Q&A

接入JDBDynamicModule后安装/编译报错

我们在接入的过程当中遇到了诸如类名和方法名冲突的问题,需要与MCube的相关负责人沟通,单独为工程进行SDK的定制化开发,解除依赖。

哪些楼层适合做成动态化楼层

就我们的经验来讲,适合做成动态化楼层需要满足以下一个或多个条件:

1.楼层的展示样式存在灵活变化的需求。

2.楼层的交互形式简单且单一。动态化着重于UI展示,相对来说模版交互事件开发较为繁琐。

3.安卓与iOS差异不大。这里的差异主要说的是模开发的差异,由于MCube本身的机制,在进行模版开发时经常会有安卓和iOS模版字段不通用的情况,具体见下面“安卓与iOS模版开发时的差异”部分。差异小可以保证安卓和iOS能采用同一套模版,减少开发工作量。

通过loadWithCallback加载模版失败

首先检查DYNContainerConfig对象的module和templateID是否设置正确。

其次检查是否实现了网络加载桥接类以及协议。MCube的所有网络请求都要经过桥接类来进行处理,走我们本地的网络请求并把结果返回给MCube。首先根据自己的命名需要创建一个类,并实现协议,在+load里对创建的类进行注册,主要是告诉MCube你的网络请求后续都由我这个类来处理

+ (void)load {
   [DYNMapperManager registeProtocolName:DYNProtocolConfig.networkProtocolName handlerClassName:NSStringFromClass(self)];
}

桥文件里的主要工作是实现协议里定义的相关方法,网络请求的DYNNetworkProtocol中主要需要实现的有:

getServerURL

根据自己的网络环境配置,返回MCube接口请求的URL头部,有两套:

1.正式环境:api.m.jd.com/XXX?functionId=

2.测试环境:beta-api.m.jd.com/XXX?functionId=

requestWithSetupModel: finish: cancel:

在这个方法里,需要创建API请求,将setupModel里的functionId和params,以及appType放进入参,发起请求,并把请求结果通过finish/cancel的Block回调返回给MCube进行处理。我们也可以在这里断点或者进行自己的处理,最主要的接口是获取模版列表,可以查看下发的模版列表文件是否正常。

getNetworkType

根据当前的网络环境返回网络类型,比如Wi-Fi,5G和4G等等。

模版中的ImageView图片无法加载

图片加载相关的请求也需要创建对应的桥接类,实现协议的相关方法。同时还需要给UIImageView创建一个category分类UIImageView+DYNBImageViewHandler,在分类里覆写dyn_setImageWithURL: placeholderImage:和dyn_setImageWithURL: placeholderImage: completed:方法,在它们里面利用sdWebImage等其他工具进行图片下载。

如何在模版中使用原生视图组件

MCube中可以将原生视图组件做为元素写到模版里,有以下步骤

1.原生视图组件实现协议里的两个方法:

#pragma mark - DYNCustomViewProtocol
- (id)getCustomView {
    return self;
}

- (void)setDataWithValue:(id)value object:(id)object sender:(DYNViewLayout *)sender {
    if ([value isKindOfClass:[原生模型 class]]) {
        //使用模型刷新原生视图组件
    }
}

2.在+load里声明模版元素与原生视图类的对应关系:

+ (void)load {
    [DYNMapperManager registeProtocolName:@"模版元素名" module:@"模块名" handlerClassName:@"原生视图组件类名"];
}


3.模版中用对应的元素名进行编写

<FlexboxLayout layoutId="999" width="match_parent" height="wrap_content" flexDirection="column" justifyContent="flex_start" bgColor="#FFFFFF">
    <模版元素名 layoutId="100" width="100%" height="100%" data="${原生模型对应key}" bgColor="#FFFFFF">
    </模版元素名>
</FlexboxLayout>

安卓与iOS模版开发时的差异

上文提到:由于MCube本身的机制,在进行模版开发时经常会有安卓和iOS模版字段不通用的情况,例如:

MCube动态化与原生工程结合最佳实践 | 京东云技术团队

MCube动态化与原生工程结合最佳实践 | 京东云技术团队

在我们的开发过程中,遇到的安卓和iOS不兼容的问题有:

1.安卓的嵌套滑动组件接入工程后,会报与本地的库有冲突。

2.FlexboxLayout 设置100%安卓可以滑动,ios滑动不了。

3.ImageView scaleType="stretch" 安卓会展示比例有问题,需要加useAspectRatio,ios没问题。

MCube动态化与原生工程结合最佳实践 | 京东云技术团队

4.安卓在设置渐变色的时候语法不生效:

MCube动态化与原生工程结合最佳实践 | 京东云技术团队

模版中如何做复杂的逻辑

1.数值结算

<ImageView height="$calc(44*SCREEN_WIDTH/375)" width="$calc(SCREEN_WIDTH)" />

2.条件判断

<ImageView src="@{${data.img1}?${data.img1}:${data.img2}}"/>
<View visibility="@{@{${data.show}!=null}?1:2}"/>

3.渐变色(拼接语法)

<FlexboxLayout bgColorList="$joint(${startColored},$unescape(comma),${endColored})">
<TextView text="$joint((${data.text1}  ${data.text2}))"/>

上传和发布模版

模版要上传到配置平台(具体网址请咨询相关负责人,并开通权限),在配置平台创建APP,模块(页面)和具体楼层,楼层可以发布不同版本,上传缩略图和模版文件,最后还可以选择白名单发布或者灰度发布。

MCube动态化与原生工程结合最佳实践 | 京东云技术团队

如何做降级方案?

降级的形式我们在不同维度设立了三套方案:

视图层面

如果MCube的SDK加载动态化视图失败,会给我们一个失败回调Block,那么我们的处理是可以利用存在DynamicViewModel里的nativeData去加载原生楼层作为降级。

下发数据层面

可以通过控制是否下发module和templateID,来控制该楼层走原生展示还是动态化展示。

业务楼层层面

我们在配置平台设置了白名单(dynamicWhiteList)进行控制:按模块名(module)-模版名(templateID)来定位具体楼层,配置true(降级)/false(动态化)决定是否降级。

数据格式:

"dynamicWhiteList":{
    "页面名module":{
        "模版templateID 1":true,//降级
        "模版templateID 2":false//动态化
    }
}

作者:京东零售 姜海

来源:京东云开发者社区 转载请注明来源

点赞
收藏
评论区
推荐文章
用户案例 | 腾讯医疗资讯平台云原生容器化之路
作者yuhuliu,腾讯研发工程师,关注存储、大数据、云原生领域。摘要医疗资讯业务在高速发展过程中,形成了覆盖不同场景、不同用户、不同渠道的几十个业务,以及上千个服务。为了高效满足用户多样化的需求,医疗技术团队通过TKE上云,使用CodingDevOps平台,以及云上可观测技术,来提升研发效率、降低运营运维成本。本文介绍我们在上云过程中一些实践和
Stella981 Stella981
3年前
Picasso:开启大前端的未来
“道生一,一生二,二生三,三生万物。”——《道德经》Picasso是大众点评移动研发团队自研的高性能跨平台动态化框架,经过两年多的孕育和发展,目前在美团多个事业群已经实现了大规模的应用。Picasso源自我们对大前端实践的重新思考,以简洁高效的架构达成高性能的页面渲染目标。在实践中,甚至可以把Native技术向P
Stella981 Stella981
3年前
Android组件化方案及组件消息总线modular
背景组件化作为Android客户端技术的一个重要分支,近年来一直是业界积极探索和实践的方向。美团内部各个Android开发团队也在尝试和实践不同的组件化方案,并且在组件化通信框架上也有很多高质量的产出。最近,我们团队对美团零售收银和美团轻收银两款AndroidApp进行了组件化改造。本文主要介绍我们的组件化方案,希望对从事Android组件化开发
撮合前端平台在低代码平台的落地实践 | 京东云技术团队
基于传统认知,前端产品直接触达消费者,往往具有高度的定制化、需求变更频繁等特点,要求具有很好的动态性,能够满足不同客户的需求。那么能否建设类似的前端中台产品,我们姑且称之为“前端领域产品”,实现接入团队端到端能力复用呢?我们在撮合业务线中进行了一系列思考和探索
京东云开发者 京东云开发者
3个月前
史无前例,移植V8虚拟机到纯血鸿蒙系统
作者:京东科技于飞跃一、背景\\\\如图所示,Roma框架是我们自主研发的动态化跨平台解决方案,已支持iOS,android,web三端。目前在京东金融APP已经有200页面,200乐高楼层使用,为保证基于Roma框架开发的业务可以零成本、无缝运行到鸿
京东云开发者 京东云开发者
2个月前
揭秘动态化跨端框架在鸿蒙系统下的高性能解决方案
作者:京东科技胡大海前言(后文统称“动态化”)是一个由京东金融大前端团队全自主研发的,一份代码,可以在HarmonyOS、iOS、Android、Web四端运行的跨平台解决方案。在研发团队使用后可大幅降低研发人力成本;为业务提供实时触达、A/B触达等能力以
京东云开发者 京东云开发者
2个月前
Code Review:探索工程实践之道
作者:京东物流冯志文前言本文参考《京东JAVA代码规范V1.1》\&Google代码评审工程实践方法论,结合团队代码评审的实践经验整理成文档,这份文档是我们团队集体经验的结晶。我相信公司其他部门也有类似的经验和最佳实践。希望通过互相交流和学习,共同提高代码
京东云开发者 京东云开发者
2星期前
Taro小程序开发性能优化实践
作者:京东零售姜海我们团队在利用Taro进行秒送频道小程序的同时,一直在探索性能优化的最佳实践。随着需求的不断迭代,项目中的性能问题难免日积月累,逐渐暴露出来影响用户体验。适逢双十一大促,我们趁着这个机会统一进行了Taro性能优化实践,现总结如下,希望能为
精彩分享 | 欢乐游戏 Istio 云原生服务网格三年实践思考
作者吴连火,腾讯游戏专家开发工程师,负责欢乐游戏大规模分布式服务器架构。有十余年微服务架构经验,擅长分布式系统领域,有丰富的高性能高可用实践经验,目前正带领团队完成云原生技术栈的全面转型。导语欢乐游戏这边对istio服务网格的引进,自2019开始,从调研到规模化落地,至今也已近三年。本文对实践过程做了一些思考总结,期望能给对网格感兴趣的同学们以参考
AMS 新闻视频广告的云原生容器化之路
作者卓晓光,腾讯广告高级开发工程师,负责新闻视频广告整体后台架构设计,有十余年高性能高可用海量后台服务开发和实践经验。目前正带领团队完成云原生技术栈的全面转型。吴文祺,腾讯广告开发工程师,负责新闻视频广告流量变现相关后台开发工作,熟悉云原生架构在生产实践中的应用,拥有多年高性能高可用后台服务开发经验。目前正推动团队积极拥抱云原生。陈宏钊,腾讯广告高级开发工程