写点什么

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

  • 2023-12-08
    北京
  • 本文字数:4145 字

    阅读完需:约 14 分钟

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

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

接入背景

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


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


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


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


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


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


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

单楼层动态化改造

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


首先,在数据层面:



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


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



通用楼层的能力包括:


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 来加载和展示楼层。流程图如下:



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


改造成果:


踩坑 Q&A

接入 JDBDynamicModule 后安装/编译报错

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

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

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


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


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


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

通过 loadWithCallback 加载模版失败

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


其次检查是否实现了网络加载桥接类以及<DYNNetworkProtocol>协议。MCube 的所有网络请求都要经过桥接类来进行处理,走我们本地的网络请求并把结果返回给 MCube。首先根据自己的命名需要创建一个类,并实现<DYNNetworkProtocol>协议,在+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 图片无法加载

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

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

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


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


#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 模版字段不通用的情况,例如:




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


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


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


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



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


模版中如何做复杂的逻辑

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


下发数据层面


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


业务楼层层面


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


数据格式:


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


作者:京东零售 姜海

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

发布于: 刚刚阅读数: 5
用户头像

拥抱技术,与开发者携手创造未来! 2018-11-20 加入

我们将持续为人工智能、大数据、云计算、物联网等相关领域的开发者,提供技术干货、行业技术内容、技术落地实践等文章内容。京东云开发者社区官方网站【https://developer.jdcloud.com/】,欢迎大家来玩

评论

发布
暂无评论
MCube动态化与原生工程结合最佳实践 | 京东云技术团队_前端_京东科技开发者_InfoQ写作社区