Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >一年撸完百万行代码,企业微信的全新鸿蒙NEXT客户端架构演进之路

一年撸完百万行代码,企业微信的全新鸿蒙NEXT客户端架构演进之路

作者头像
JackJiang
发布于 2025-04-15 03:33:40
发布于 2025-04-15 03:33:40
5420
举报
文章被收录于专栏:即时通讯技术即时通讯技术

本文由企业微信客户端团队黄玮分享,原题“在流沙上筑城:企微鸿蒙开发演进”,下文进行了排版优化和内容修订。

1、引言

当企业微信团队在2024年启动鸿蒙Next版开发时,我们面对的是双重难题:

  • 1)在WXG小团队模式下,如何快速将数百万行级企业应用移植到全新操作系统?
  • 2)在鸿蒙API 还是Preview的初期,如何保持业务代码的稳定,在API快速更新的浪潮中岿然不动?

DataList框架给出了破局答案(即通过三重机制构建数字负熵流):

  • 1)结构化熵减:将业务逻辑渲染到UI的过程抽象为数据流,使鸿蒙与Android共享同一套数据驱动的开发机制;
  • 2)动态熵减:通过抽象出来的UI数据层屏蔽鸿蒙API的变化,让业务代码历经三个版本的UI层大改而不受影响;
  • 3)认知熵减:将跨平台差异封装为一系列通用组件,降低开发者心智负荷,可以专注于业务开发而不用关心技术变更。

本文将要分享的是企业微信的鸿蒙Next客户端架构的演进过程,面对代码移植和API不稳定的挑战,提出了DataList框架解决方案。通过结构化、动态和认知三重熵减机制,将业务逻辑与UI解耦,实现数据驱动开发。采用MVDM分层架构(业务实体层、逻辑层、UI数据层、表示层),屏蔽系统差异,确保业务代码稳定。

2、企业微信客户端框架进化史

罗马不是一天建成的,我们在开发框架方面,也经历了 发现问题、探索方案 、优化改进 的过程。

野蛮生长(2019年前):

  • 1)背景:团队缺乏统一规范,开发风格各异;
  • 2)问题:相同功能重复实现,维护成本高。

初步探索(2019-2022):

  • 1)背景:急需统一开发范式,提高开发效率;
  • 2)实现:EasyList框架,提出"一切皆列表"理念,封装模板代码,让开发者专注于业务开发;
  • 3)问题:未严格隔离业务与UI,退化为MVC模式;抽象能力不足,组件复用率极低。

渐入佳境(2022-2024):

  • 1)创新:实现了基于数据驱动/分层隔离的DataList框架;
  • 2)价值:框架提供抽象能力,降低开发认知负担;让每一个组件都具备复用能力,极大提高了复用率,助力通用组件从个位数突破至50+。

3、企业微信客户端框架整体设计

3.1 整体架构设计

DataList是一套基于数据驱动的分层隔离框架,整体架构图如下图所示。

▲ 图1:DataList MVVM架构图

接下来将从数据流向、分层架构的角度分别对这张图进行讲解。

3.2 数据流向设计

从数据流向的角度,DataList框架可以简单分为Data/List两部分:

  • 1)List:业务逻辑部分,简单来说就是业务数据如何转换为UI数据;
  • 2)Data:数据驱动部分,UI数据如何渲染为实际的UI/如何驱动UI刷新。

▲ 图2:DataList数据流向图

3.3 MVDM环形分层设计

DataList通过将业务数据到UI数据的转换逻辑独立出来,系统形成了清晰的边界层次:

  • 1)业务实体层(Repo):负责请求数据,拿到业务数据(保持稳定);
  • 2)业务逻辑层(ViewModel):处理业务逻辑,负责业务数据到UI数据的转换(保持稳定);
  • 3)UI数据层(CellData/ViewData):对UI层的抽象(内部适应变化,对外接口稳定);
  • 4)表示层(Cell):处理具体UI渲染(拥抱变化,适配平台新特性)。

相当于MVVM(Model-View-ViewModel)变成了MVDM(Model-View-Data-ViewModel)。

箭头代表依赖指向:

▲ 图3:DataList环形分层图

这里介绍下UI数据层。

将整个控件数据化,即为ViewData:

export class TextData extends BaseData {   text?: string | Resource   fontColor?: ResourceColor   fontSize?: number | string | Resource   fontWeight?: number | FontWeight | string

将多个ViewData组合起来,成为一个组件CellData:

//由Image+Text组成 export class ImgTextCellData extends BaseCellData {   builder: WrappedBuilder<[]> = wrapBuilder(ImgTextCellBuilder)   root: RowData   img?: ImgData //对应Image控件   text?: TextData //对应Text控件 }

由于CellData内不含任何业务代码,所以不受限于业务,天然可以复用。下图是组件复用统计(现有58个组件,数千次复用)。

▲ 图4:通用组件复用统计

这样分层的好处:

  • 1)方便UI大规模复用;
  • 2)跨平台代码一致性;
  • 3)隔离业务与UI,UI层变动不影响业务逻辑。

3.4 无可删减:DataList开发示例

完美的达成,不在于无可增添,而在于无可删减。 ——《风沙星辰》 安托万·德·圣-埃克苏佩里

梳理一下,开发一个业务需求,哪些部分是无可删减的?

其实就是业务相关的部分:

  • 1)数据请求;
  • 2)业务数据转为UI(UI数据)。

这些都是必须由开发者填写的逻辑,这些步骤框架最多只能简化,不能代劳。

比如:我们开发一个极简版本的人员列表,看下对应步骤。

数据请求:

//Repo对应Model层 class DemoContactRepo():IListRepository<DemoContactReq,DemoContactRsp> {     override fun requestData(         req: DemoContactReq,//请求参数         callback: (rsp: DemoContactRsp) -> Unit,//结果回调         errorCallback: (errorCode: Int, errorMsg: Any?) -> Unit//错误回调     ) {         //请求数据,返回         ContactService.getContact(req){contacts->             callback(contacts)         }     } }

数据转换

//继承自单数据源列表基类,泛型指明请求与返回的业务数据类型 class DemoContactViewModel: SingleListViewModel<DemoContactReq, DemoContactRsp>() {      /**      * 业务数据转为UI数据      */     overridefun transferData(data: DemoContactRsp): List<ICellData> {         returndata.contacts.map {             ImgPhotoTextImgCellData( //通用组件                 dataId = it.id,                 photo = PhotoData(url = it.avatar),//一个图片控件                 leftText = TextData(text = it.name))//一个文本控件         }     }     /**      * 拉取数据所用的仓库(对应Model层)      */     overridefun initRepository(): IListRepository<DemoContactReq, DemoContactRsp> {         return DemoContactRepo()     }     /**      * 初次或刷新页面时的请求参数      */     overridefun refreshParam(arguments: Bundle?): DemoContactReq {         return DemoContactReq(0,20)     } }

算上注释,「总计39行」,一个极简版联系人列表就开发完成了。

▲ 图5:DataList联系人 Demo

如果是一个本地静态页面,可以去掉网络请求部分,直接堆砌通用组件(CellData)即可,完整代码只要40行。

//继承自本地静态列表基类,无数据请求 class DemoAttendanceViewModel:LocalSingleListViewModel() {     //...     //&#128295; 乐高式组件拼装     overridefun transformCellDataList(): List<ICellData> {         return listOf(             attendanceCellData("打卡人员","员工A").section(1),             attendanceCellData("规则名称","打卡规则abc").section(1),             attendanceCellData("规则类型","固定上下班").section(2),             attendanceCellData("打卡时间","周一至周五,09:00-10:00").section(2),             attendanceCellData("打卡方式","手机+智慧考勤机").section(3),             attendanceCellData("打卡位置","天府三街198号").section(3),             attendanceCellData("打卡Wi-Fi", "未设置").section(3),             attendanceCellData("打卡设备", "").section(3),             TextCellData(TextData.tips("位置和Wi-Fi满足任意一项即可打卡")).noneDivider(),             attendanceCellData("加班规则","以加班申请为准").section(4),             attendanceCellData("更多设置","").section(5),             ButtonCellData(ButtonData("删除规则", buttonStyle = R.style.button_l_white, textColor = R.color.day_night_color_chrome_red.getColor())).section(6))     }     //对通用Cell的简单封装     privatefun attendanceCellData(title:String,desc:String):ImgPhotoTextImgCellData{         return ImgPhotoTextImgCellData(/*设置属性*/)     } }

▲ 图6:DataList静态列表 Demo

3.5 MVDM架构的延迟决策实践

如果想设计一个便于推进各项工作的系统,其策略就是要在设计中尽可能长时间地保留尽可能多的可选项。 ——《整洁架构之道》

通过MVDM分层架构,我们构建了业务逻辑与UI渲染的解耦机制。但真正的考验来自鸿蒙Next开发——当底层API如流沙般变动时,如何保持上层建筑的稳定?

通过UI数据层的隔离,MVDM的UI层历经三个大版本的架构演进,业务层仍保持稳定:

  • 1)妥协版:快速启动业务开发;
  • 2)适配版:拥抱动态属性能力;
  • 3)优化版:突破性能瓶颈。

这三次蜕变完美诠释了"流沙筑城"的技术哲学:在持续变化的基础设施上,通过架构设计构建确定性。接下来我们将深入每个阶段的演变历程。

4、第一版:系统限制下的妥协

4.1 目标:快速启动

由于我们所有页面都基于DataList开发,需要尽快实现数据绑定能力,让业务开发可以启动。

4.2 实现思路

鸿蒙和Compose一样,UI组件是函数而不是类,没办法像Android那样,拿到控件的对象进行赋值。

@Component export struct DemoPage{     build(){         Text("Hello World!") //这是一个函数,没法拿到它的对象,也就没法进行动态赋值     } }

如果要实现数据与UI的绑定,只能在这里对所有属性进行遍历调用.。

4.3 技术方案

在现有API的基础上,我们只能实现这个方案。

▲ 图7:数据绑定第一版

直接把所有属性列出来,全部调一遍,如果data里对应属性没有赋值,就相当于用null调用了一次。

4.4 实践问题

这个方案有很多问题:

  • 1)即使我在Data里只设置了一个属性,也需要执行一遍所有函数;
  • 2)某些属性函数,用null调用和不调用,表现是不一样的,这种属性无法列出;
  • 3)太丑,不优雅。

我们迫切需要一个能动态设置属性的方案,因此我向华为官方提出了需求。

▲ 图8:向华为提需求

这个需求交付之后,就有了第二版。

5、第二版:动态属性下的数据绑定

5.1 接入动态属性设置能力

之前提的需求,华为给的解决方案是AttributeModifer。

这是官网的介绍:

▲ 图9:Modifier能力介绍

5.2 技术方案

接入AttributeModifer后,UI层的写法如下:

@Component export struct WwText { @ObjectLink data: TextData @State modifier: TextModifier = new TextModifier(new TextData())   aboutToAppear(): void {     this.modifier.data = this.data   }   build() {     Text(this.data.text)     .attributeModifier(this.modifier) //通过modifier更新属性,不必再调其他函数   } }

这里更新的原理大致如下图:

▲ 图10:第二版更新机制

TextData被@Observed注解之后,实际上是被动态代理了:

  • 1)代理类观察到属性变化;
  • 2)从记录的set里找到观察者;
  • 3)调用观察者的更新函数(实际流程比较复杂,很多调用);
  • 4)这个更新函数里面就会执行Modifier里面的applyNormalAttribute函数,最后将属性动态设置到控件上。

WwText编译后的ts代码如下:

//WWText.ts export class WwText extends ViewPU {     //...     initialRender() {         this.observeComponentCreation2((elmtId, isInitialRender) => {             //这里就是会刷新的部分             Text.create(this.data.text);             Text.attributeModifier.bind(this)(ObservedObject.GetRawObject(this.modifier));         }, Text);         Text.pop();     } }

5.3 实践问题

实际使用中发现,这套方案有两方面很显著的问题。

1)问题1:代码膨胀:

在实际应用这些Ww系列封装组件的场景,可以看到编译后的代码膨胀的非常明显,两行编译后变成了二十行。

▲ 图11:ets源码/ts产物

一个通用组件,编译后从4k变成了75k。

▲ 图12:编译后体积变化

问题2:性能消耗:

这个写法的性能也非常差,主要是三个方面。

1)冗余刷新:

在applyAttribute这里,如果TextData里面设置了10个属性,但是本次只更新了一个属性,那么在触发更新之后,仍然会10个属性都重新设置一遍。

export class TextModifier extends BaseModifier<TextAttribute> { //...      applyAttribute(instance: TextAttribute, data: TextData) {     super.applyAttribute(instance, data)     if (data.fontColor || data.fontColor == 0) {       instance.fontColor(data.fontColor)     }     if (data.textAlign) {       instance.textAlign(data.textAlign)     }     //...   } }

2)状态管理:

现在鸿蒙这套状态管理机制,在DataList数据绑定的场景下性能不足。查了一下鸿蒙状态管理机制的源码,状态变量是通过动态代理来感知属性变化的,具体一点就是通过SubscribableHandler来代理属性的set、get等操作,源码如下。

class SubscribableHandler{     get(target,property,receiver){         //...         switch(property){             default:                 const result = Reflect.get(target,property,receiver)//反射获取属性                 if(/*...*/){                     let isTracked = this.isPropertyTracked(target, propertyStr);                     this.readCbFunc_.call(this.obSelf_, receiver, propertyStr, isTracked);                 }         }     } }

经过测试:这个get函数的耗时为万次9ms。而我们的Modifier里面恰好有很多if,需要拿值来判断。

简单算一下,一个页面10个cell,每个cell5个Text,每个Text23个属性+45个基础属性:

一次刷新get次数 = 10X5X(23+45) = 3400次 3400/10000X9 = 3ms

也就是说,没有执行任何具体逻辑,只是取值判断,就消耗了「3ms」。而鸿蒙120帧率的情况,一帧的渲染时间也只有8.3ms。

3)节点增多:

对原生控件进行包装后(Text ==> WwText),View树里会增加一个节点(橙色)。如果某些情况图方便给外层组件又设置了属性,还会再额外增加一个渲染节点(红色)。

比如下面这个组件:

Column(){     WwText({data:this.data1}).width("100%")     WwText({data:this.data2}) }

对应的View树如下:

▲ 图13:节点增多示意

节点从两个变成了五个,而鸿蒙的渲染性能优化就是要求节点越少越好。

6、第三版:基于自定义状态管理的性能优化

6.1 目标:性能优化

第三版的目标就是解决第二版的诸多问题,进行性能优化。

6.2 实现思路

针对这些问题,分析的思路如下:

▲ 图14:第三版问题分析

6.3 技术方案

1)去掉控件包装:

前面提到使用包装控件有两个弊端:

  • 1)编译后的代码增加,体积增大;
  • 2)增加节点,消耗性能。

因此,我们决定去掉包装,使用原生控件。

那么有两个问题:

  • 1)原本的控件基础逻辑放哪里(比如WwPhoto里加载图片的逻辑);
  • 2)之前提到,我们用AttributeModifier时,控件的属性函数我们可以动态调用,但是构造函数不行,那如何更新构造函数?

这两个问题都可以用 AttributeUpdater来解决,它是AttributeModifier的子类。

划重点:

▲ 图15: AttributeUpdater说明-划重点

去掉包装类之后,原本放到包装类里面的基础逻辑,可以放到对应的Updater里面。

例如:

  • 1)WwText ==> Text + TextUpdater;
  • 2)WwPhoto ==> Image + PhotoUpdater。

2)自定义状态管理:

升级为Updater之后,如果对应的Data仍然是状态变量,那么我们去get的时候消耗依旧。 这里先解释一下,为什么我们的Data要加@Observed注解。

按官方的用法,只有多层嵌套监听的场景才需要@Observed注解

其实这里是因为我们的所有业务逻辑都在ViewModel里面,而不是按照官方方案放在Page里。就会存在修改无法被感知的问题,如下图所示。

▲ 图16:为何要加@Observed

说回正题,既然要去掉这个官方的状态管理,那么就有两处改动:

  • 1)去掉Data上的@Observed注解;
  • 2)在View里面不再加状态注解。

那么,如何驱动UI刷新?

正好,AttributeUpdater里面可以直接拿到attribute对象,可以通过这个对象直接设置属性,那么问题就回到了如何感知Data属性的变更。

正常情况首先想到的就是TypeScript的动态代理,即Proxy,鸿蒙的状态管理就是这么做的,其实现基于前文提到的SubscribableHandler,里面用了反射,性能不足。想要不反射,要么就字符串匹配,依次调用对应函数,既然如此,不如彻底一点,直接使用静态代理。

export class BaseData //view的实例,由Update赋值和清理   ins?:INS //用于刷新构造函数   updateConstructorFunc?: () =>void private _width?: Length private _height?: Length //... set width(width: Length|undefined) {     this._width = width     this.ins?.width(width) //设置属性时直接设置到view上   } get width():Length|undefined{     returnthis._width   } //...

最后,配套Updater的实现如下:

export class BaseUpdater> extends AttributeUpdater<T, C> {   data?: DATA constructor(data?: DATA) {     super()     this.data = data   } //用于批量刷新所有已设置的属性,上屏或reuse时触发   updateData(data?: DATA, instance?: T): BaseUpdater<DATA, T, C> {     //...     this.setUpdateFunc(this.data, ins)     if (ins) {       this.applyAttribute(ins, this.data)       this.refreshConstructor()     }     returnthis   } //设置属性   applyAttribute(instance: CommonAttribute, data: BaseData) {     if (data.width || data.width == 0) {       instance.width(data.width)     }     if (data.height || data.height == 0) {       instance.height(data.height)     }     //...   } }

第三版的改动总结如下:

▲ 图17:第三版改动总结

这些改动之后,通用组件内部UI层的实现也需修改:

@Component export struct ImgTextCell { @Consume@Watch("updateData") cellData: ImgTextCellData   rootUpdater = new RowUpdater()   imgUpdater = new ImageUpdater()   textUpdater = new TextUpdater()   aboutToAppear() {     this.updateData()   }   aboutToReuse() {     this.updateData()   }   build() {     Row() {       Image(ImageUpdater.EMPTY).attributeModifier(this.imgUpdater)       Text().attributeModifier(this.textUpdater)     }.attributeModifier(this.rootUpdater)   } //data与updater绑定 private updateData() {     this.rootUpdater.updateData(this.cellData.root)     this.imgUpdater.updateData(this.cellData.img)     this.textUpdater.updateData(this.cellData.text)   } }

虽然Cell内部实现变化很大,但是对业务方来说,CellData和Data的对外使用方法没有变化。

Data与Updater为何要分开。

其实这里的Cell写法看起来还是有优化空间的,比如你可能会想到,为何不把Data和Updater结合到一起,比如:

export class BaseData extends BaseUpdater{     //...    }

然后Cell的写法就可以简化成:

@Component export struct ImgTextCell {   @Consume cellData: ImgTextCellData   build() {     Row() {       Image(ImageUpdater.EMPTY).attributeModifier(this.cellData.img)       Text().attributeModifier(this.cellData.text)     }.attributeModifier(this.cellData.root)   } }

分两种情况讨论一下:

  • 1)修改Data内部的值:这两种写法,都是通过AttributeUpdater内部的attribute对象进行更新,都是改那个更新哪个,没毛病;
  • 2)增/删/改 Data对象本身。

▲ 图18:修改 Data 本身的两种情况

6.3 升级效果

1)体积降低:

以PhotoTextCell为例,升级之后代码编译后的体积明显降低了,仅为升级前的9.3%。

可以再对比下编译后的内容。

ets源码:

build() {   Row() {     Image("").attributeModifier(this.imgUpdater)     Text().attributeModifier(this.textUpdater)   }.attributeModifier(this.rootUpdater) }

ts产物:

initialRender() {     this.observeComponentCreation2((elmtId, isInitialRender) => {         Row.create();         Row.attributeModifier.bind(this)(this.rootUpdater);     }, Row);     this.observeComponentCreation2((elmtId, isInitialRender) => {         Image.create("");         Image.attributeModifier.bind(this)(this.imgUpdater);     }, Image);     this.observeComponentCreation2((elmtId, isInitialRender) => {         Text.create();         Text.attributeModifier.bind(this)(this.textUpdater);     }, Text);     Text.pop();     Row.pop(); }

可以看到编译产物少了很多层嵌套,代码结构清爽多了,我们的hap当时改完之后体积直接少了「十几M」。

2)性能提升:

升级之后性能也有明显提升:

  • 1)通用组件PhotoTextCell的复用耗时从4.3ms降低到0.9ms;
  • 2)首页的会话列表,复用的帧率由卡顿的32帧提升到丝滑的118帧。

由于鸿蒙的动态帧率机制,118其实就是滑动时满帧。

▲ 图19:升级前后帧率对比

7、本文小结

在鸿蒙生态快速迭代的"流沙"环境下,DataList框架通过三重熵减机制构建了确定性开发范式,鸿蒙DataList的三次技术演进本质是一场对抗API不确定性的架构实践。

简单总结一下:

1)第一版(妥协版):基于API遍历属性实现基础数据绑定,虽快速启动业务开发但存在冗余调用与性能隐患;

2)第二版(适配版):引入AttributeModifier动态属性机制,可进行属性的动态更新,却因状态管理机制本身的性能消耗和控件包装导致代码膨胀与性能劣化;

3)第三版(优化版):创新采用自定义状态管理,剥离包装层直接操作原生控件,结合AttributeUpdater实现静态代理与精准属性更新,使通用组件编译体积缩减至9.3%、复用耗时降低79%,帧率从32帧跃升至118帧。

三次架构升级始终贯彻MVDM分层理念,通过UI数据层的隔离,实现业务逻辑零修改适配UI层巨变。包含这三次主要的升级在内,过去一年DataList的UI层经历了十多次改动(包括API变化与对鸿蒙了解更深入而进行的性能优化)。这些变更揭示了"流沙筑城"的核心逻辑:「表层拥抱变化,中层消化冲击,核心业务层保持稳定」。(本文已同步发布于:http://www.52im.net/thread-4812-1-1.html)

UI数据层在此场景中负责消化技术变化带来的冲击,允许团队:

  • 1)通过接口抽象延迟具体实现决策;
  • 2)在知识完备后通过实现替换进行渐进式优化;
  • 3)保持核心业务代码的语义稳定性。

这些最终让企业微信鸿蒙团队于2024年底完成了企业微信鸿蒙NEXT第一版「100万行,600+页面」的开发,并成功发布。

至此,关于企业微信鸿蒙NEXT开发架构演进讲解完毕。

8、相关资料

[1] 微信纯血鸿蒙版正式发布,295天走完微信14年技术之路!

[2] 鸿蒙NEXT如何保证应用安全:详解鸿蒙NEXT数字签名和证书机制

[3] 开源IM聊天程序HarmonyChat:基于鸿蒙NEXT的WebSocket协议

[4] 大型IM工程重构实践:企业微信Android端的重构之路

[5] 企业微信的IM架构设计揭秘:消息模型、万人群、已读回执、消息撤回等

[6] 企业微信针对百万级组织架构的客户端性能优化实践

[7] 企业微信客户端中组织架构数据的同步更新方案优化实战

[8] 微信团队分享:微信支付代码重构带来的移动端软件架构上的思考

[9] 微信团队原创分享:微信客户端SQLite数据库损坏修复实践

[10] 从客户端的角度来谈谈移动端IM的消息可靠性和送达机制

[11] 爱奇艺技术分享:爱奇艺Android客户端启动速度优化实践总结

[12] 伪即时通讯:分享滴滴出行iOS客户端的演进过程

[13] 移动端IM实践:Android版微信如何大幅提升交互性能(一)

[14] 百度公共IM系统的Andriod端IM SDK组件架构设计与技术实现

[15] 首次公开,最新手机QQ客户端架构的技术演进实践

[16] IM开发干货分享:有赞移动端IM的组件化SDK架构设计实践

[17] 马蜂窝旅游网的IM客户端架构演进和实践总结

[18] 蘑菇街基于Electron开发IM客户端的技术实践

[19] IM开发干货分享:我是如何解决大量离线消息导致客户端卡顿的

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
首次公开,最新手机QQ客户端架构的技术演进实践
接上篇《总是被低估,从未被超越,揭秘QQ极致丝滑背后的硬核IM技术优化》,本文则将重点介绍手机 QQ 客户端技术架构升级背后的故事。
JackJiang
2024/05/30
7690
首次公开,最新手机QQ客户端架构的技术演进实践
企业微信 iOS 工程演进之路(一)- 组件化
导语:本文介绍了企业微信 iOS 端工程近一年的演进方向,随着业务快速迭代企业微信 iOS 端已经成长为一个大型项目,去年我们还接入了腾讯会议、腾讯文档、企业邮箱等插件,为了适应业务的高速发展,我们进行了组件化、插件集成能力建设、Bazel 迁移等工作。
腾讯TMF团队
2022/12/15
1.7K1
鸿蒙 模仿boss直聘客户端更新教程【鸿蒙专题4】
各位同学大家好 ,之前写过一篇鸿蒙模仿boss直聘文章。那个时候我自己天真的以为鸿蒙里面没有类似安卓里面的fragment,所以就用布局显示隐藏来实现的 虽然效果是实现了但是并不是很理想 ,因为所有的逻辑都是写在同一个Ability 视图里面,当逻辑复杂了我们就很难处理了,不过之前·我查文档发现鸿蒙提供了 Fraction 小部分这个控件给我们开发使用,所以就更新一下之前的模仿boss直聘的客户端项目 那么废话不多说,我们正式开始。
徐建国
2021/12/16
7530
鸿蒙 模仿boss直聘客户端更新教程【鸿蒙专题4】
鸿蒙OS架构设计探秘:从分层设计到多端部署
最近两年来,我一直在跟进鸿蒙系统的发展,从EMUI到HarmonyOS,见证了这个国产操作系统从无到有的成长历程。今天想和大家分享一下我对鸿蒙系统架构的理解和实践心得。
熊文豪
2025/03/26
1470
鸿蒙OS架构设计探秘:从分层设计到多端部署
常见鸿蒙应用开发面试题
.markdown-body{word-break:break-word;line-height:1.75;font-weight:400;font-size:16px;overflow-x:hidden;color:#252933}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{line-height:1.5;margin-top:35px;margin-bottom:10px;padding-bottom:5px}.markdown-body h1{font-size:24px;line-height:38px;margin-bottom:5px}.markdown-body h2{font-size:22px;line-height:34px;padding-bottom:12px;border-bottom:1px solid #ececec}.markdown-body h3{font-size:20px;line-height:28px}.markdown-body h4{font-size:18px;line-height:26px}.markdown-body h5{font-size:17px;line-height:24px}.markdown-body h6{font-size:16px;line-height:24px}.markdown-body p{line-height:inherit;margin-top:22px;margin-bottom:22px}.markdown-body img{max-width:100%}.markdown-body hr{border:none;border-top:1px solid #ddd;margin-top:32px;margin-bottom:32px}.markdown-body code{word-break:break-word;border-radius:2px;overflow-x:auto;background-color:#fff5f5;color:#ff502c;font-size:.87em;padding:.065em .4em}.markdown-body code,.markdown-body pre{font-family:Menlo,Monaco,Consolas,Courier New,monospace}.markdown-body pre{overflow:auto;position:relative;line-height:1.75}.markdown-body pre>code{font-size:12px;padding:15px 12px;margin:0;word-break:normal;display:block;overflow-x:auto;color:#333;background:#f8f8f8}.markdown-body a{text-decoration:none;color:#0269c8;border-bottom:1px solid #d1e9ff}.markdown-body a:active,.markdown-body a:hover{color:#275b8c}.markdown-body table{display:inline-block!important;font-size:12px;width:auto;max-width:100%;overflow:auto;border:1px solid #f6f6f6}.markdown-body thead{background:#f6f6f6;color:#000;text-align:left}.markdown-body tr:nth-child(2n){background-color:#fcfcfc}.markdown-body td,.markdown-body th{padding:12px 7px;line-height:24px}.markdown-body td{min-width:120px}.markdown-body blockquote{color:#666;padding:1px 23px;margin:22px 0;border-left:4px solid #cbcbcb;background-color:#f8f8f8}.markdown-body blockquote:after{display:block;content:""}.markdown-body blockquote>p{margin:10px 0}.
万少
2025/03/27
3340
常见鸿蒙应用开发面试题
小红书APP的全新鸿蒙NEXT端性能优化技术实践
性能和体验在 iOS / Android 双端场景下已经是一个较为成熟的话题,但随着鸿蒙 OS 的发展,端侧开发者需要更多的关注多端场景的差异性。
JackJiang
2025/05/19
3660
小红书APP的全新鸿蒙NEXT端性能优化技术实践
从0到1:微信后台系统的演进之路
“ 2个月的开发时间,微信后台系统经历了从0到1的过程。从小步慢跑到快速成长,经历了平台化到走出国门,微信交出的这份优异答卷,解题思路是怎样的?本文由张文瑞,微信后台团队出品。 从无到有 2011.1.21 微信正式发布。这一天距离微信项目启动日约为2个月。就在这2个月里,微信从无到有,大家可能会好奇这期间微信后台做的最重要的事情是什么? 我想应该是以下三件事: 1 确定了微信的消息模型 微信起初定位是一个通讯工具,作为通讯工具最核心的功能是收发消息。微信团队源于广硏团队,消息模型跟邮箱的邮件模型也很有渊
腾讯大数据
2023/03/03
1.8K0
从0到1:微信后台系统的演进之路
探索Android复杂页面管理之道-QQ音乐播放页代码演进之路
前言 播放页是QQ音乐内曝光量最大的二级页,是端内展示歌曲信息、提供播控操作、进行推荐宣发的重要入口。随着QQ音乐的快速发展,播放页也从一个简单播控页面逐渐演变到了现在业务众多、UI多变的复杂页面。在该转变的过程中,播放页Android端的代码也根据不同时期的需要,进行了持续演进。本文将简要回顾Android端播放页代码在过去不同时期的结构特点,并重点介绍在最近一次代码结构调整中,我们探索出的一种适合多人开发和代码复用的复杂页面管理模式。 图 1: QQ音乐播放页 背景 MVC 在QQ音乐发展之初,播
QQ音乐技术团队
2021/07/23
4K1
企业微信针对百万级组织架构的客户端性能优化实践
相对于传统的消费级IM应用,企业级IM应用的特殊之外在于它的用户关系是按照所属企业的组织架构来关联的起来,而组织架构的大小是无法预设上限的,这也要求企业级IM应用在遇到真正的超大规模组织架构时,如何保证它的应用性能不受限于(或者说是尽可能不受限于)企业架构规模,这是个比较有难度的技术问题。
JackJiang
2023/09/21
4360
企业微信针对百万级组织架构的客户端性能优化实践
鸿蒙 模仿boss直聘客户端实现教程【鸿蒙专题6】
大家好。我是坚果,这是我的公众号“坚果前端”,觉得不错的话,关注一下吧,如果你迷惘,不妨看看码农的轨迹
徐建国
2021/12/24
6090
鸿蒙  模仿boss直聘客户端实现教程【鸿蒙专题6】
企业微信超大型工程-跨全平台UI框架最佳实践
一. 背景 企业微信的跨平台之路 企业微信作为跨android、ios、mac、pc、web五个端,超千万行代码的超大型工程,每一个需求迭代周期,都需要5端同步开发、发版,不管是对于开发,还是产品、设计、测试来说,都是一个巨大的挑战。 企业微信初期架构设计上就将底层网络、db以及大部分业务逻辑都抽离到c++实现,以供多平台复用。但是UI还是各平台独自处理,从开发的角度来看,移动端的android、ios,电脑端的mac、pc,同样的界面布局,却需要写两套逻辑代码,因此,ui的跨平台诉求是我们的一大痛点
微信终端开发团队
2021/09/23
4.7K0
鸿蒙(HarmonyOS)应用性能优化实战-组件复用四板斧
在滑动场景下,常常会对同一类自定义组件的实例进行频繁的创建与销毁。此时可以考虑通过组件复用减少频繁创建与销毁的能耗。组件复用时,可能存在许多影响组件复用效率的操作,本篇文章将重点介绍如何通过组件复用四板斧提升复用性能。
小帅聊鸿蒙
2024/10/16
2700
鸿蒙(HarmonyOS)应用性能优化实战-组件复用四板斧
HTTP客户端演进之路
HTTP 协议可能是现在 Internet 上使用得最多、最重要的协议了,越来越多应用程序需要直接通过 HTTP 协议来访问网络资源。一般的情况下我们都是使用浏览器来访问一个 WEB 服务器,用来浏览页面查看信息或者提交一些数据、文件上传下载等等。不通过浏览器来访问服务器的资源呢?一种常见的场景是,通过向另一个 http 服务器发送请求,获得数据。最常规的做法是使用同步 http 请求的方式,即下文展示的同步模式。
深度学习与Python
2021/12/09
7000
HTTP客户端演进之路
鸿蒙5开发宝藏案例分享---应用架构实战技巧
​**​大家好!​**​ 今天咱们聊聊鸿蒙开发中那些“官方文档提了但实际开发难找”的架构设计技巧。结合官方文档,我会用​**​真实代码案例+通俗讲解​**​,帮你把分层架构和线程通信落地到项目里,告别“理论会了,代码不会”的尴尬!
陈杨
2025/06/17
2160
ApkBus|聊聊大型 APP 架构演进之路
昨天的ApkBus Android开发者论坛上海站 本人分享了关于架构的东西,晚上有很多听众微信给我说“有没有具体的文章出来啊,PPT看的有点不过瘾”,本文以大会上分享的课题为蓝图,专门写个文章出来, 错过的朋友可以回顾一下!
开发者技术前线
2020/11/23
1.3K0
ApkBus|聊聊大型 APP 架构演进之路
使用 Taro 开发鸿蒙原生应用 —— 探秘适配鸿蒙 ArkTS 的工作原理
在上一篇文章中,我们已经了解到华为即将发布的鸿蒙操作系统《纯血版本——鸿蒙 Next》,以及各个互联网厂商开展鸿蒙应用开发的消息。其中,Taro作为一个重要的前端开发框架,也积极适配鸿蒙的新一代语言框架 —— ArkTS。
winty
2023/12/12
2.1K0
使用 Taro 开发鸿蒙原生应用 —— 探秘适配鸿蒙 ArkTS 的工作原理
鸿蒙 List 组件解析:从基础列表到高性能界面开发指南
在鸿蒙应用开发体系中,列表布局是处理结构化数据展示的核心场景。从新闻资讯的信息流、电商平台的商品陈列到任务管理的待办事项,几乎所有中大型应用都依赖高效的列表组件实现数据可视化。鸿蒙提供的 List、ListItem、ListItemGroup 三件套组件,通过标准化的接口设计与分层架构,构建了一套完整的列表解决方案。本文将系统解析这三个组件的核心机制、进阶用法与工程实践,帮助开发者掌握高性能列表开发的鸿蒙范式。
谢道韫
2025/06/27
1370
浅析鸿蒙 JavaScript GUI 技术栈
众所周知,刚刚开源的「鸿蒙 2.0」以 JavaScript 作为 IoT 应用开发的框架语言。这标志着继 SpaceX 上天之后,JavaScript 再一次蹭到了新闻联播级的热点。这么好的机会,只拿来阴阳怪气实在太可惜了。作为科普,这篇文章不会拿着放大镜找出代码中的槽点来吹毛求疵,而是希望通俗地讲清楚它所支持的 GUI 到底是怎么一回事。只要对计算机基础有个大概的了解,应该就不会对本文有阅读上的障碍。
zz_jesse
2020/09/17
1.9K0
浅析鸿蒙 JavaScript GUI 技术栈
企业微信Flutter与大型Native工程跨四端融合实践
作者:yamichonghe,腾讯 WXG 客户端开发工程师 跨平台开发框架是客户端领域的经典课题,几乎从操作系统诞生开始就是我们软件从业者们的思考命题。为了促进 Flutter 在 4 个端的成熟,企业微信研发团队也和 Google 团队针对电脑端 Flutter 稳定版的落地做了多轮技术沟通。终于在近期的版本实现同一个功能跨平台 4 端同步上线。企业微信每一个迭代都需要确保 iOS、Android、Windows、Mac 四个客户端平台的版本功能完全一致,版本发布时间一致。这是非常大的挑战。任何研发投入
腾讯技术工程官方号
2023/02/13
3.6K0
企业微信Flutter与大型Native工程跨四端融合实践
开源轻量级IM框架MobileIMSDK的鸿蒙NEXT客户端库已发布
MobileIMSDK-鸿蒙端是一套基于鸿蒙Next(纯血鸿蒙)系统的IM即时通讯客户端库:
JackJiang
2024/12/23
2470
开源轻量级IM框架MobileIMSDK的鸿蒙NEXT客户端库已发布
推荐阅读
相关推荐
首次公开,最新手机QQ客户端架构的技术演进实践
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档