随着业务的插件程发展及版本迭代,客户端工程中不断增加新的化工业务逻辑、引入新的文件WhatsApp%E3%80%90+86%2015855158769%E3%80%91hoisting%20license%20class%20ma资源,随之而来的瘦身问题就是安装包体积变大,前期各个业务模块通过无用资源删减、技术大图压缩或转上云、插件程AB 实验业务逻辑下线或其他手段在降低包体积上取得了一定的化工成果。 在瘦身的文件过程中我们关注到了 R 文件瘦身的概念,目前京东 APP 是瘦身支持插件化的,有业务插件工程、技术宿主工程,插件程对业务插件包文件进行分析,化工发现除了常规的文件资源及代码外,R 类文件大概占包体积的瘦身 3%~5% 左右,对宿主工程包文件进行分析,技术R 类文件占比也有 3% 左右。我们先后在对 R 类文件瘦身的可行性及业界开源项目进行调研后,探索出了一套适用于插件化工程的WhatsApp%E3%80%90+86%2015855158769%E3%80%91hoisting%20license%20class%20ma R 文件瘦身技术方案。 理论基础 —R 文件 R 文件也就是我们日常工作中经常打交道的 R.java 文件,在 开发规范中我们需要将应用中用到的资源分别放入专门命名的资源目录中,外部化应用资源以便对其进行单独维护。
外部化应用资源后,我们可在项目中使用 R 类 ID 来访问这些资源,且 R 类 ID 具有唯一性。 class { @ void (@ ) { super.(); (R..); 在 apk 打包流程中 R 类文件是由 aapt( Asset Tool)工具打包生成的,在生成 R 类文件的同时对资源文件进行编译,生成 .arsc 文件,.arsc 文件相当于一个文件索引表,应用层代码通过 R 类 ID 可以访问到对应的资源。
R 文件瘦身的可行性分析 日常开发阶段,在主工程中通过 R.xx.xx 的方式引用资源,经过编译后 R 类引用对应的常量会被编译进 class 中。 (); 这种变化叫做内联,内联是 java 的一种机制(如果一个常量被标记为 final,在 java 编译的过程中会将常量内联到代码中,减少一次变量的内存寻址)。 非主工程中,R 类资源 ID 以引用的方式编译进 class 中,不会产生内联。 (R..); 产生这种现象的原因是 AGP 打包工具导致的。具体细节,大家可以去查阅一下 在 R 文件上的处理过程。 结论:R 类 id 内联后程序可运行,但并非所有的工程都会自动产生内联现象,我们需要通过技术手段在合适的时机将 R 类 id 内联到程序中,内联完成后,由于不再依赖 R 类文件,则可以将 R 类文件删除,在应用正常运行的同时,达到包瘦身目的。 插件化工程 R 文件瘦身实战 制定技术方案 目前京东 客户端是支持插件化的,整个插件化工程包含公共库(是一个 aar 工程,用来存放组件和宿主共用的类和资源)、业务插件(插件工程是一个独立的工程,编译产物可以运行在宿主环境中)、宿主(主工程,提供运行环境)。在插件化的过程中为了防止宿主和插件资源冲突,通过修改插件 保证了资源的唯一性。由于公共资源库、宿主是被很多业务依赖,对这两个项目进行改动评估影响涉及比较多,插件一般都是业务模块自行维护,不存在被依赖问题,所以先在业务插件模块进行 R 类瘦身实践。 对业务插件工程打出的包进行反编译以后,发现 R 类 ID 无内联现象,且 R 类文件具有一定的大小,对包内的 R 文件进行分析,发现 R 文件中仅包含业务自身的资源,不包含业务依赖的公共资源 R 类。 View ( , , ) { this.b = .(R.., , false); this.h = ()this.b.(R.id.); this.f = ()this.b.(R.id.);}
结合对业界开源项目的调研分析,尝试制定符合京东商城的技术方案并优先在业务插件内完成 R 类 ID 内联并删除对应的 R 文件。 1. 通过 api 收集要处理的 class 文件 是 提供的操作字节码的一种方式,它在 class 编译成 dex 之前通过一系列 处理来实现修改.class 文件。 @ void ( ) , , { super.(); // 通过.()获取输入文件,有两种 // 以源码方式参与编译的目录结构及目录下的文件 // 以jar包方式参与编译的所有jar包 = new (.().size()); = new (.().size()); = .(); for ( input : ) { = input.(); for ( : ) { .add(.()); = input.(); for ( : ) { .add(.()); 2. 对收集到的.class 文件结合 ASM 框架进行分析处理 ASM 是一个操作 Java 字节码的类库,通过 ASM 我们可以方便对.class 文件进行修改。 优先识别 R 类文件,通过 访问 R.class 文件,读取文件中的静态常量,进行临时变量存储: @ (int , name, desc, , value) { //R类中收集 final int 对应的变量 if (.() && .() &&.() &&.isInt(desc)) { .(, name, value); } super.(, name, desc, , value);} 非 R 类文件,通过 识别到代码中的 R 类引用,获取引用对应的值,进行 id 值替换: @ void (int , owner, name, desc) { if ( == .) { //owner:包名;name:具体变量名;value:R类变量对应的具体id值 value = .(owner, name); if (value != null) { //调用该api实现值替换 mv.(value); ; super.(, owner, name, desc); * 注:以上代码仅为部分示意代码,非正式插件代码。 在业务模块引入 R 类瘦身插件后,业务模块功能可正常运行,且插件包大小均有 3%~5% 不同程度的减少。 公共资源 R 类 ID 内联 由于在京东 客户端代码中,更多的资源文件集中在公共资源库中,相对的公共库生成的 R 类文件也更大,对编译后的 apk 包内容进行分析后,公共资源库的 R 类文件占比高达 3%。 公共库跟随宿主一起打包,在宿主打包过程中引入 R 类瘦身插件,打包后的 apk 有明显的减小,手机安装 apk 后启动首页正常展示无问题,但在打开某些业务插件时,会有异常闪退现象,崩溃类型为 R.x not found。对崩溃原因分析如下:业务插件代码中使用了公共库中的 R 类资源、插件打包流程独立于宿主打包,在插件打包的过程中仅完成了业务模块 R 类的内联,并没有考虑到公共资源 R 类的内联,基于上述原因当宿主打包过程完成 R 类文件删除瘦身后,我们在运行某业务插件的过程中,自然就会报公共资源 R 类找不到的问题从而产生崩溃。
为了解决这个问题一开始的方案设想是增加白名单机制,keep 住所有被业务模块使用的公共资源,但很快这个想法就被推翻,公共资源存在本身就是希望各个业务模块直接引用这部分资源,而不是自己定义,如果 keep 住的话,必然有很大一部分的资源无法删减,瘦身的效果会大打折扣。 既然保留的方案并不合适,那就将公共资源 R 类 id 也内联到代码中去。前面提到京东是支持插件化的,整个插件化方案是基于 aura 平台实现的,我们向 aura 团队进行了咨询,然后 get 到了新的方案切入点。 aura 平台在插件化的过程中已通过 aapt2 引入了公共资源 id 固定的能力,在该能力下,已定义的公共资源 id 会一直固定 (各个业务插件中引用的公共资源 id 一致),且公共资源库中已有的资源不可被其他模块重复定义,否则会覆盖之前已定义好的资源,基于上述的结果和规则,我们对之前的 R 文件瘦身 功能进行完善,将公共资源的 R 类 id 内联到项目中。 利用 appt2 的 - -ids 和 - emit-ids 两个参数实现固化资源 id 的功能,并将将固化后的 ids 文件命名为 .xml 存储在公共资源库中,业务插件依赖公共资源库,在打包编译的过程中 aura 会将 .xml 复制到业务工程临时编译文件夹 下的指定位置并参与业务模块的打包过程中,其文件内容格式如下:
修改 R 文件瘦身 代码,从指定位置读取并识别这部分公共资源,按照 的形式进行变量存储,并在后续过程中对业务模块中的公共资源部分进行 id 替换。 Map parse() { if (in == null) { null; ry = ry.(); = .(); doc = .parse(in); = doc.(); list = .(); ; R 类资源 id 内联部分代码如下: void (int , owner, name, desc) { if ( == .) { //优先从业务模块R类资源中查找 value = .(owner, name); if (value != null) { mv.(value); ; //从公共R类资源中查找 value = (name); if (value != null) { mv.(value); ; super.(, owner, name, desc); 该方案完善后,结合商详业务插件进行了验证,在商详及宿主均完成 R 文件内联瘦身后,商详模块业务功能可正常使用,无异常现象。 考虑到 R 文件内联瘦身 是在打包编译阶段引入的,我们也统计了一下引入该插件以后对打包时长的影响,数据如下:
结合数据来看,引入 R 文件瘦身插件后对整体打包时长并无显著影响。 至此,基于京东商城探索的插件化工程 R 文件瘦身 就开发完成,目前已在部分业务插件模块进行了线上验证,在功能上线以后我们也及时的进行了崩溃观测以及用户反馈的跟进,暂无异常问题。当然围绕 R 文件瘦身缩减包体积这个目的,开发人员有各种各样的技术方案,上述方案不一定适用于所有的客户端开发体系,另外后续也将围绕包瘦身这一常态事务建设一系列的相关工具,介入工作当中的各个阶段,高效、有效的控制包体积的增长,如大家在瘦身方面有相关建议和想法也欢迎大家来一起讨论。 参考文章: : : APK 构建流程: #build- |
开工!涉及香洲79个老旧小区!医我看|跨境就医更便利!香港奶奶在珠海重获“膝”望莆推行“公转商”贴息贷款 业内:可缓解排队现象城厢区第一实验小学与砺成中学间 将新建停车场全市首创!斗门区实施工业废水“协商排放”新模式仙游:妻子吸毒后性情大变 丈夫含泪报警要求复婚不成 仙游一男子持刀刺死前妻最高检发布10件生态环境检察典型案例最高检发布10件生态环境检察典型案例抱着玻璃奶瓶玩 莆田3岁女童遭“割喉”i帮忙|珠海“侨心工程”让爱延续 助力近3700名学子圆梦唐涛个展将在上海开幕:臆动着的真实 收藏资讯谁在疯狂买艺术品?交易热潮把市场推上巅峰,这波趋势别错过! 收藏资讯智慧无限:古代玉器展览将开幕 收藏资讯全市首创!斗门区实施工业废水“协商排放”新模式马树青个展劳作将于明日开幕 收藏资讯莆田:嫂子酒驾撞死人 小叔子顶包近400亿人次!1至7月我国交通出行火热企业可申请技改投资基金谁在疯狂买艺术品?交易热潮把市场推上巅峰,这波趋势别错过! 收藏资讯医我看|被蚂蚁咬了别拖延!症状会延后 第一时间如何处理?香洲区一民宅失火,3名被困人员获救!无人伤亡徐锦江艺术展落幕 亲自上阵做雕塑模特 收藏资讯莆田仙游:电动车撞昏摩托骑手后逃逸莆田严查“两客一危” 1周10辆违规长途车受罚抱着玻璃奶瓶玩 莆田3岁女童遭“割喉”三亚文化周巅峰艺术展举办 收藏资讯摩的为揽客占领公交站:站台揽客40辆摩的被查处央·美术馆关注年轻创作力量 收藏资讯莆田:金价回暖 市民“抄底”黄金投资孙捷当代首饰个展将举办 收藏资讯“七八分饱”到底怎么界定?学会这3招真能瘦商务部:境外人士可以在自贸试验区开立证券账户或期货账户莆田一小区二次供水池锈迹斑斑 卫生堪忧许江笔下的葵花即将盛开在上海中华艺术宫 收藏资讯冬日在龙美术馆遇见奈良美智 百余精美藏品现身 收藏资讯荔城区水务局项目办原主任 李国富受贿获刑国家发改委新型城镇化综合试点第三方评估组来莆医我看|处暑宜赶“秋老虎”,这两个穴位可滋阴润燥刘邓艺术展熵迹将举办 收藏资讯加兰德末节轰27分,三分14中10砍下赛季首个50+《火爆狂飙:天堂》作者团队新项目停摆 开发人员遭解雇世体:西班牙国家队本周一集中,开启世界杯的征程算力数独什么时候出 公测上线时间预告勇者战影什么时候出 公测上线时间预告妙弹连珠什么时候出 公测上线时间预告《ARC Raiders》AI机甲自我进化成精 甚至学会炸服跳跃游侠晚报:Epic下周喜加一曝光?《银河战士P4》萨姆斯新形象惊艳荣誉&钱!世界杯历届冠军奖金:今4200万美元最高,40年飙涨20倍游侠晚报:《流放之路2》正式版延期!NS2向下兼容更新