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

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

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

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

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 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
企业微信针对百万级组织架构的客户端性能优化实践
相对于传统的消费级IM应用,企业级IM应用的特殊之外在于它的用户关系是按照所属企业的组织架构来关联的起来,而组织架构的大小是无法预设上限的,这也要求企业级IM应用在遇到真正的超大规模组织架构时,如何保证它的应用性能不受限于(或者说是尽可能不受限于)企业架构规模,这是个比较有难度的技术问题。
JackJiang
2023/09/21
3990
企业微信针对百万级组织架构的客户端性能优化实践
鸿蒙 模仿boss直聘客户端实现教程【鸿蒙专题6】
大家好。我是坚果,这是我的公众号“坚果前端”,觉得不错的话,关注一下吧,如果你迷惘,不妨看看码农的轨迹
徐建国
2021/12/24
5910
鸿蒙  模仿boss直聘客户端实现教程【鸿蒙专题6】
小红书APP的全新鸿蒙NEXT端性能优化技术实践
性能和体验在 iOS / Android 双端场景下已经是一个较为成熟的话题,但随着鸿蒙 OS 的发展,端侧开发者需要更多的关注多端场景的差异性。
JackJiang
2025/05/19
1180
小红书APP的全新鸿蒙NEXT端性能优化技术实践
拥抱国产化:转转APP的鸿蒙NEXT端开发尝鲜之旅
2023 年在华为开发者大会(HDC.Together)上,除了面向消费者的 HarmonyOS 4 之外,华为还推出了面向开发者的 HarmonyOS Next 开发者预览。
JackJiang
2025/04/23
1880
拥抱国产化:转转APP的鸿蒙NEXT端开发尝鲜之旅
鸿蒙 模仿boss直聘客户端更新教程【鸿蒙专题4】
各位同学大家好 ,之前写过一篇鸿蒙模仿boss直聘文章。那个时候我自己天真的以为鸿蒙里面没有类似安卓里面的fragment,所以就用布局显示隐藏来实现的 虽然效果是实现了但是并不是很理想 ,因为所有的逻辑都是写在同一个Ability 视图里面,当逻辑复杂了我们就很难处理了,不过之前·我查文档发现鸿蒙提供了 Fraction 小部分这个控件给我们开发使用,所以就更新一下之前的模仿boss直聘的客户端项目 那么废话不多说,我们正式开始。
徐建国
2021/12/16
7290
鸿蒙 模仿boss直聘客户端更新教程【鸿蒙专题4】
鸿蒙(HarmonyOS)应用性能优化实战-组件复用四板斧
在滑动场景下,常常会对同一类自定义组件的实例进行频繁的创建与销毁。此时可以考虑通过组件复用减少频繁创建与销毁的能耗。组件复用时,可能存在许多影响组件复用效率的操作,本篇文章将重点介绍如何通过组件复用四板斧提升复用性能。
小帅聊鸿蒙
2024/10/16
2120
鸿蒙(HarmonyOS)应用性能优化实战-组件复用四板斧
微信纯血鸿蒙版正式发布,295天走完微信14年技术之路!
这是一款产品,也不仅仅是一款产品。开发它的本质,是让两个高速前进,相互影响的复杂系统,彼此磨合和熟悉,像是执行一场空中加油任务。
JackJiang
2025/01/10
3680
微信纯血鸿蒙版正式发布,295天走完微信14年技术之路!
前端-微信小程序开发(2):小程序基本介绍
前面我们研究了下微信小程序的执行流程,因为拿不到源码,只能算我们的猜想,我们需要更加了解小程序还需要做具体的项目,于是我们将原来那套还算复杂的业务拿出来:
grain先森
2019/03/29
1.8K0
前端-微信小程序开发(2):小程序基本介绍
请来围观:WPF开发的微信客户端!!!
公司的同事离职了,接下来的日子可能会忙碌,能完善DEMO的时间也会少了,因此,把做的简易DEMO整体先记录一下,等后续不断的完善。
沙漠尽头的狼
2022/06/13
1.9K0
请来围观:WPF开发的微信客户端!!!
首次公开,最新手机QQ客户端架构的技术演进实践
接上篇《总是被低估,从未被超越,揭秘QQ极致丝滑背后的硬核IM技术优化》,本文则将重点介绍手机 QQ 客户端技术架构升级背后的故事。
JackJiang
2024/05/30
6170
首次公开,最新手机QQ客户端架构的技术演进实践
大型IM工程重构实践:企业微信Android端的重构之路
企业微信本地部署版(下文简称为本地版)是从2017年起,脱胎于企业微信的一款产品。本地版的后台服务能独立部署在政府或者大型企业的本地服务器上。在一个已经迭代了7年的大型Android端工程中,企业微信本地版不可避免地会暴露出一些遗留系统的特点。
JackJiang
2024/04/01
1780
大型IM工程重构实践:企业微信Android端的重构之路
基于小程序技术栈的微信客户端跨平台实践
本文主要内容整理自 GMTC 2019 分享《基于小程序技术栈的微信客户端跨平台实践》  https://gmtc2019.geekbang.org/presentation/1711 一、前言 ---- 小程序自诞生以来,经过两年多的发展,成为了微信开发者生态中最具有生命力的一环,为外部开发者开辟了全新的想象空间。然而,小程序带来的改变绝不仅限于微信之外,小程序技术栈的确立,又对微信客户端的研发产生了怎样的影响? 二、微信客户端的跨平台实践 ---- 微信客户端团队,早在 2012 年的时候就已经开始
微信终端开发团队
2019/07/02
6.1K1
基于小程序技术栈的微信客户端跨平台实践
OpenHarmony应用全局的UI状态存储:AppStorage
AppStorage是应用全局的UI状态存储,是和应用的进程绑定的,由UI框架在应用程序启动时创建,为应用程序UI状态属性提供中央存储。
小帅聊鸿蒙
2025/05/15
1210
OpenHarmony应用全局的UI状态存储:AppStorage
鸿蒙HarmonyOS应用开发 | 「鸿蒙技术分享」HarmonyOS NEXT元服务卡片实战体验
HarmonyOS NEXT 是华为鸿蒙系统的最新版本,带来了更为流畅、高效的体验,并以元服务卡片(Service Widget)为核心,优化了服务分发和交互体验。本文将从开发者的角度,分享如何开发和部署元服务卡片,并结合代码实例,带你体验全新的卡片开发流程。
一键难忘
2024/12/21
3630
干货 | 携程鸿蒙应用开发实践
作者简介 Gordon,携程资深移动开发工程师,关注鸿蒙开发。 背景 作为全球领先的一站式旅游服务平台,携程始终坚持以技术创新为发展核心。自鸿蒙发布以来,我们便投入研发力量进行调研、开发,并成功落地了携程机票项目、服务卡片项目等。现将鸿蒙项目中相关经验整理分享,希望能给大家一些参考,也希望鸿蒙发展能越来越好。 一、鸿蒙系统简介 华为鸿蒙HarmonyOS系统是面向万物互联的全场景分布式操作系统,目前鸿蒙系统已从2.0升级更新至Beta 3.0,支持手机、平板、智能穿戴、智慧屏等多种终端设备运行,提供应用开
携程技术
2022/07/19
1.6K0
干货 | 携程鸿蒙应用开发实践
企业微信Flutter与大型Native工程跨四端融合实践
作者:yamichonghe,腾讯 WXG 客户端开发工程师 跨平台开发框架是客户端领域的经典课题,几乎从操作系统诞生开始就是我们软件从业者们的思考命题。为了促进 Flutter 在 4 个端的成熟,企业微信研发团队也和 Google 团队针对电脑端 Flutter 稳定版的落地做了多轮技术沟通。终于在近期的版本实现同一个功能跨平台 4 端同步上线。企业微信每一个迭代都需要确保 iOS、Android、Windows、Mac 四个客户端平台的版本功能完全一致,版本发布时间一致。这是非常大的挑战。任何研发投入
腾讯技术工程官方号
2023/02/13
3.4K0
企业微信Flutter与大型Native工程跨四端融合实践
开源轻量级IM框架MobileIMSDK的鸿蒙NEXT客户端库已发布
MobileIMSDK-鸿蒙端是一套基于鸿蒙Next(纯血鸿蒙)系统的IM即时通讯客户端库:
JackJiang
2024/12/23
1900
开源轻量级IM框架MobileIMSDK的鸿蒙NEXT客户端库已发布
【愚公系列】《AIGC辅助软件开发》012-AI辅助客户端编程:AI辅助 Android 应用开发
文章链接:https://cloud.tencent.com/developer/article/2472464
愚公搬代码
2024/11/30
3220
企业微信超大型工程-跨全平台UI框架最佳实践
一. 背景 企业微信的跨平台之路 企业微信作为跨android、ios、mac、pc、web五个端,超千万行代码的超大型工程,每一个需求迭代周期,都需要5端同步开发、发版,不管是对于开发,还是产品、设计、测试来说,都是一个巨大的挑战。 企业微信初期架构设计上就将底层网络、db以及大部分业务逻辑都抽离到c++实现,以供多平台复用。但是UI还是各平台独自处理,从开发的角度来看,移动端的android、ios,电脑端的mac、pc,同样的界面布局,却需要写两套逻辑代码,因此,ui的跨平台诉求是我们的一大痛点
微信终端开发团队
2021/09/23
4.6K0
华为鸿蒙 HarmonyOS 开发资料全面汇总
本示例基于 OpenHarmony 下的 JavaScript UI 框架,进行项目目录解读,JS FA、常用和自定义组件、用户交互、JS 动画的实现,通过本示例可以基本了解和学习到 JavaScript UI 的开发模式。
wscats
2022/05/05
3.5K0
推荐阅读
相关推荐
企业微信针对百万级组织架构的客户端性能优化实践
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档