您現(xiàn)在的位置是:時(shí)尚 >>正文
插件化工程WhatsApp%E3%80%90+86%2015855158769%E3%80%91hoist%20the%20colours%20piano%20sheet%20musicR文件瘦身技术方案
時(shí)尚5人已圍觀
簡(jiǎn)介 原標(biāo)題:插件化工程R文件瘦身技術(shù)方案 | 京東云技術(shù)團(tuán)隊(duì)隨著業(yè)務(wù)的發(fā)展及版本迭代,客戶端工程中不斷增加新的業(yè)務(wù)邏輯、引入新的資源,隨之而來的問題就是安裝包體積變大,前期各個(gè)業(yè)務(wù)模塊通過無用資源 ...
?
原标题:插件化工程R文件瘦身技术方案 | 京东云技术团队
随着业务的插件程发展及版本迭代,客户端工程中不断增加新的化工业务逻辑、引入新的文件WhatsApp%E3%80%90+86%2015855158769%E3%80%91hoist%20the%20colours%20piano%20sheet%20music资源,随之而来的瘦身问题就是安装包体积变大,前期各个业务模块通过无用资源删减、技术大图压缩或转上云、插件程AB 实验业务逻辑下线或其他手段在降低包体积上取得了一定的化工成果。
在瘦身的文件过程中我们关注到了 R 文件瘦身的概念,目前京东 APP 是瘦身支持插件化的,有业务插件工程、技术宿主工程,插件程对业务插件包文件进行分析,化工发现除了常规的文件资源及代码外,R 类文件大概占包体积的瘦身 3%~5% 左右,对宿主工程包文件进行分析,技术R 类文件占比也有 3% 左右。我们先后在对 R 类文件瘦身的可行性及业界开源项目进行调研后,探索出了一套适用于插件化工程的WhatsApp%E3%80%90+86%2015855158769%E3%80%91hoist%20the%20colours%20piano%20sheet%20music R 文件瘦身技术方案。
理论基础 —R 文件
R 文件也就是我们日常工作中经常打交道的 R.java 文件,在 Android 开发规范中我们需要将应用中用到的资源分别放入专门命名的资源目录中,外部化应用资源以便对其进行单独维护。

外部化应用资源后,我们可在项目中使用 R 类 ID 来访问这些资源,且 R 类 ID 具有唯一性。
public class MainActivity extends BaseActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
在 android apk 打包流程中 R 类文件是由 aapt(Android Asset Packaing Tool)工具打包生成的,在生成 R 类文件的同时对资源文件进行编译,生成 resource.arsc 文件,resource.arsc 文件相当于一个文件索引表,应用层代码通过 R 类 ID 可以访问到对应的资源。

R 文件瘦身的可行性分析
日常开发阶段,在主工程中通过 R.xx.xx 的方式引用资源,经过编译后 R 类引用对应的常量会被编译进 class 中。
setContentView(2131427356);
这种变化叫做内联,内联是 java 的一种机制(如果一个常量被标记为 static final,在 java 编译的过程中会将常量内联到代码中,减少一次变量的内存寻址)。
非主工程中,R 类资源 ID 以引用的方式编译进 class 中,不会产生内联。
setContentView(R.layout.activity_main);
产生这种现象的原因是 AGP 打包工具导致的。具体细节,大家可以去查阅一下 android gradle plugin 在 R 文件上的处理过程。
结论:R 类 id 内联后程序可运行,但并非所有的工程都会自动产生内联现象,我们需要通过技术手段在合适的时机将 R 类 id 内联到程序中,内联完成后,由于不再依赖 R 类文件,则可以将 R 类文件删除,在应用正常运行的同时,达到包瘦身目的。
插件化工程 R 文件瘦身实战
制定技术方案
目前京东 Android 客户端是支持插件化的,整个插件化工程包含公共库(是一个 aar 工程,用来存放组件和宿主共用的类和资源)、业务插件(插件工程是一个独立的工程,编译产物可以运行在宿主环境中)、宿主(主工程,提供运行环境)。在插件化的过程中为了防止宿主和插件资源冲突,通过修改插件 packageId 保证了资源的唯一性。由于公共资源库、宿主是被很多业务依赖,对这两个项目进行改动评估影响涉及比较多,插件一般都是业务模块自行维护,不存在被依赖问题,所以先在业务插件模块进行 R 类瘦身实践。
对业务插件工程打出的包进行反编译以后,发现 R 类 ID 无内联现象,且 R 类文件具有一定的大小,对包内的 R 文件进行分析,发现 R 文件中仅包含业务自身的资源,不包含业务依赖的公共资源 R 类。
public View onCreateView(LayoutInflater paramLayoutInflater, ViewGroup paramViewGroup, Bundle paramBundle) {
this.b = paramLayoutInflater.inflate(R.layout.lib_pd_main_page, paramViewGroup, false);
this.h = (PDBuyStatusView)this.b.findViewById(R.id.pd_buy_status_view);
this.f = (PageRecyclerView)this.b.findViewById(R.id.lib_pd_recycle_view);}

结合对业界开源项目的调研分析,尝试制定符合京东商城的技术方案并优先在业务插件内完成 R 类 ID 内联并删除对应的 R 文件。
1. 通过 transform api 收集要处理的 class 文件
Transform 是 Android Gradle 提供的操作字节码的一种方式,它在 class 编译成 dex 之前通过一系列 Transform 处理来实现修改.class 文件。
@Override
public void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {
super.transform(transformInvocation);
// 通过TransformInvocation.getInputs()获取输入文件,有两种
// DirectoryInpu以源码方式参与编译的目录结构及目录下的文件
// JarInput以jar包方式参与编译的所有jar包
allDirs = new ArrayList<>(invocation.getInputs().size());
allJars = new ArrayList<>(invocation.getInputs().size());
Collection
for (TransformInput input : inputs) {
Collection
for (DirectoryInput directoryInput : directoryInputs) {
allDirs.add(directoryInput.getFile());
}
Collection
for (JarInput jarInput : jarInputs) {
allJars.add(jarInput.getFile());
}
}
}
2. 对收集到的.class 文件结合 ASM 框架进行分析处理
ASM 是一个操作 Java 字节码的类库,通过 ASM 我们可以方便对.class 文件进行修改。
优先识别 R 类文件,通过 ClassVisitor 访问 R.class 文件,读取文件中的静态常量,进行临时变量存储:
@Overridepublic FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { //R类中收集 public static final int 对应的变量 if (JDASMUtil.isPublic(access) && JDASMUtil.isStatic(access) &&JDASMUtil.isFinal(access) &&JDASMUtil.isInt(desc)) { jdRstore.addInlineRField(className, name, value); } return super.visitField(access, name, desc, signature, value);}
非 R 类文件,通过 MethodVisitor 识别到代码中的 R 类引用,获取引用对应的值,进行 id 值替换:
@Override
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
if (opcode == Opcodes.GETSTATIC) {
//owner:包名;name:具体变量名;value:R类变量对应的具体id值
Object value = jdRstore.getRFieldValue(owner, name);
if (value != null) {
//调用该api实现值替换
mv.visitLdcInsn(value);
return;
}
}
super.visitFieldInsn(opcode, owner, name, desc);
}
* 注:以上代码仅为部分示意代码,非正式插件代码。

在业务模块引入 R 类瘦身插件后,业务模块功能可正常运行,且插件包大小均有 3%~5% 不同程度的减少。
公共资源 R 类 ID 内联
由于在京东 android 客户端代码中,更多的资源文件集中在公共资源库中,相对的公共库生成的 R 类文件也更大,对编译后的 apk 包内容进行分析后,公共资源库的 R 类文件占比高达 3%。
公共库跟随宿主一起打包,在宿主打包过程中引入 R 类瘦身插件,打包后的 apk 有明显的减小,手机安装 apk 后启动首页正常展示无问题,但在打开某些业务插件时,会有异常闪退现象,崩溃类型为 R.x resource not found。对崩溃原因分析如下:业务插件代码中使用了公共库中的 R 类资源、插件打包流程独立于宿主打包,在插件打包的过程中仅完成了业务模块 R 类的内联,并没有考虑到公共资源 R 类的内联,基于上述原因当宿主打包过程完成 R 类文件删除瘦身后,我们在运行某业务插件的过程中,自然就会报公共资源 R 类找不到的问题从而产生崩溃。

为了解决这个问题一开始的方案设想是增加白名单机制,keep 住所有被业务模块使用的公共资源,但很快这个想法就被推翻,公共资源存在本身就是希望各个业务模块直接引用这部分资源,而不是自己定义,如果 keep 住的话,必然有很大一部分的资源无法删减,瘦身的效果会大打折扣。
既然保留的方案并不合适,那就将公共资源 R 类 id 也内联到代码中去。前面提到京东是支持插件化的,整个插件化方案是基于 aura 平台实现的,我们向 aura 团队进行了咨询,然后 get 到了新的方案切入点。
aura 平台在插件化的过程中已通过 aapt2 引入了公共资源 id 固定的能力,在该能力下,已定义的公共资源 id 会一直固定 (各个业务插件中引用的公共资源 id 一致),且公共资源库中已有的资源不可被其他模块重复定义,否则会覆盖之前已定义好的资源,基于上述的结果和规则,我们对之前的 R 文件瘦身 gralde plugin 功能进行完善,将公共资源的 R 类 id 内联到项目中。
利用 appt2 的 - stable-ids 和 - emit-ids 两个参数实现固化资源 id 的功能,并将将固化后的 ids 文件命名为 shared_res_public.xml 存储在公共资源库中,业务插件依赖公共资源库,在打包编译的过程中 aura 会将 shared_res_public.xml 复制到业务工程临时编译文件夹 intermediates 下的指定位置并参与业务模块的打包过程中,其文件内容格式如下:

修改 R 文件瘦身 gradle plugin 代码,从指定位置读取并识别这部分公共资源,按照
public Map
if (in == null) {
return null;
}
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(in);
Element rootElement = doc.getDocumentElement();
NodeList list = rootElement.getChildNodes();
return resNode;
}
}

R 类资源 id 内联部分代码如下:
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
if (opcode == Opcodes.GETSTATIC) {
//优先从业务模块R类资源中查找
Object value = jdRstore.getRFieldValue(owner, name);
if (value != null) {
mv.visitLdcInsn(value);
return;
}
//从公共R类资源中查找
value = getPublicRFileValue(name);
if (value != null) {
mv.visitLdcInsn(value);
return;
}
}
super.visitFieldInsn(opcode, owner, name, desc);
}
该方案完善后,结合商详业务插件进行了验证,在商详及宿主均完成 R 文件内联瘦身后,商详模块业务功能可正常使用,无异常现象。
考虑到 R 文件内联瘦身 gradle plugin 是在打包编译阶段引入的,我们也统计了一下引入该插件以后对打包时长的影响,数据如下:

结合数据来看,引入 R 文件瘦身插件后对整体打包时长并无显著影响。
至此,基于京东商城探索的插件化工程 R 文件瘦身 gradle plugin 就开发完成,目前已在部分业务插件模块进行了线上验证,在功能上线以后我们也及时的进行了崩溃观测以及用户反馈的跟进,暂无异常问题。当然围绕 R 文件瘦身缩减包体积这个目的,开发人员有各种各样的技术方案,上述方案不一定适用于所有的客户端开发体系,另外后续也将围绕包瘦身这一常态事务建设一系列的相关工具,介入工作当中的各个阶段,高效、有效的控制包体积的增长,如大家在瘦身方面有相关建议和想法也欢迎大家来一起讨论。
参考文章:
Gradle Plugin:
https://docs.gradle.org/current/userguide/custom_plugins.html
Gradle Transform:
https://developer.android.com/reference/tools/gradle-api/7.0/com/android/build/api/transform/Transform
APK 构建流程:
https://developer.android.com/studio/build/index.html?hl=zh-cn#build-process
作者:耿蕾 田创新 来源:京东云开发者社区返回搜狐,查看更多
责任编辑:
Tags:
轉(zhuǎn)載:歡迎各位朋友分享到網(wǎng)絡(luò),但轉(zhuǎn)載請(qǐng)說明文章出處“呼來喝去網(wǎng)”。http://www.qaqo.com.cn/news/30f31899651.html
相關(guān)文章
美图秀秀默认语言在哪里修改
時(shí)尚美图秀秀是一款很厉害的美颜软件,是很多喜欢拍照的人都会用到的,使用美图秀秀的人很多,一些用户对于英语会熟悉一些,很多人都想知道美图秀秀默认语言在哪里修改?小编为各位搜集整理了一些美图秀秀修改默认语言教 ...
【時(shí)尚】
閱讀更多U号租英雄联盟手游如何租号
時(shí)尚在的教程与平台一览,帮助玩家轻松获取心仪的账号,享受游戏的无限可能。u号租英雄联盟手游租号教程与平台一览一、注册与登录u号租平台1. 访问u号租官方网站或下载u号租app。2. 点击“注册”按钮,填写 ...
【時(shí)尚】
閱讀更多沙欣发布会:今天早上听说莱曼批评我,我忍不住笑出了声
時(shí)尚11月5日讯多特蒙德将在本轮欧冠迎战奥地利球队格拉茨风暴,赛前,多特主帅沙欣、中场萨比策出席新闻发布会。沙欣谈伤员沙欣:“已知的缺阵球员仍然没有变化。我不认为会有人回归。明天我们将知道谁可以上场。”萨 ...
【時(shí)尚】
閱讀更多
熱門文章
最新文章
友情鏈接
- 预防胃痛发生,日常吃什么比较好,教你缓解胃痛的小妙招
- 英国兄弟乐队Bee Gees主唱Robin Gibb因癌症去世
- 陈冠希挑逗女艺人 女方经纪人回应:短信是真的
- 河南全省未来两天无明显强降水
- 别再找错正规脐血库地址了,在全国范围内只有7家
- 记者:埃泽渴望加盟热刺,两家俱乐部的谈判已进入关键阶段
- 13国青少年携专利参加2021智博会青少年专利孵化展
- 产妇月子餐好吃又营养,不放盐可不是正确的做法!
- 菲总统阿基诺与韩裔女主播分手 第18段恋情结束
- 怀孕前三个月食补攻略:这款菠菜鸡蛋汤必不可少
- B超怎么监测排卵?过程中的这些小细节你一定要了解
- 马奎尔:阿森纳是英超最强的球队之一,我们一直与他们竞争激烈
- 努诺:我们的阵容准备并不理想,在转会市场仍需更多动作
- 利用球童获取优势,阿斯顿维拉遭受英超罕见处罚
- 官方:英格兰U21主力哈钦森加盟诺丁汉森林,签约五年
- 9月陈冠希将在台湾办摄影展 找人冲洗相片没阴影
- 吃枸杞有哪些好处?生食和泡水,哪种效果更好
- 菲总统阿基诺与韩裔女主播分手 第18段恋情结束
- 菲总统阿基诺与韩裔女主播分手 第18段恋情结束
- 别再找错正规脐血库地址了,在全国范围内只有7家
- 13国青少年携专利参加2021智博会青少年专利孵化展
- 看数据!美国SDFC医院试管成功率高达80%真不是“吹”的
- 网传冯绍峰与谋女郎倪妮逛街戴情侣戒 正处热恋
- 蔡依林盼40岁前生小孩 称不会赴旧爱周杰伦婚礼
- 再曝巩俐怀孕 港媒称其穿球鞋围巾遮肚孕味极浓
- 梦回2022!里沙利松几乎复刻世界杯时的倒钩破门
- B超怎么监测排卵?过程中的这些小细节你一定要了解
- 阿联酋一直是共建“一带一路”的拥护者支持者
- 编剧于正斥责女星耍大牌:连狗都要住500元的酒店
- 戛纳电影节中国女星斗艳 网友批穿得好不如演得好
- 《浮城谜事》主演郝蕾郝蕾:偷情的男人没安全感
- 哪个更帅?里沙利松在英超首轮侧钩破门,与2022世界杯凌空侧钩很相似
- 杨幂刘恺威用英语晒幸福惹笑柄 网友吐槽没文化
- “包拯很黑”闹剧爆红网络 何炅谢娜搞笑编段子
- 菲总统阿基诺与韩裔女主播分手 第18段恋情结束
- 月经排干净后,白带有异味,是什么情况?如何改善
- 梦回世界杯!理查利森凌空侧勾破门梅开二度,库杜斯助攻双响
- 马奎尔:阿森纳是英超最强的球队之一,我们一直与他们竞争激烈
- 传李嘉欣流产经纪人不作回应 5个月内孕情起跌不定
- 人工授精须知!术前20多种检查不可少,15天就可完成
- 克拉克斯顿是得到西亚卡姆的关键
- 世界银行1.5亿美元助力斯里兰卡清洁能源转型?
- 纳帅不排除剥夺诺伊尔队长袖标,下赛季基米希可能接任
- 还是欧盟施压见效快 苹果正研究iPhone与其它手机互传数据
- 索尼Xperia1 Ⅵ手机不卖中国了?太过“做自己”,国人不买账!
- 618马力!Model 3高性能版参数曝光
- 罗林斯将接受右脚骨折修复手术
- RWE澳大利亚1GW西奥多陆上风电项目获州规划批准
- 内马尔本周一已恢复集体训练,可出战与马赛的法国国家德比
- 卢卡&欧文组合首秀最早将在对阵国王的比赛