当前位置: 首页 > Web前端 > HTML

Android包大小优化第1部分-资源混淆优化

时间:2023-03-28 18:25:52 HTML

指南:什么时候优化包大小?一般在app的初始阶段,由于业务代码较少,包体积较小,相应的,此时优化包体积的收益也较小。当业务逐渐成熟,迭代次数逐渐增多,包大小也会逐渐增大。增加包的大小主要影响以下几个方面:1:如果是针对app,会影响下载转化率,但是手白内部直播是插件,所以转化没有问题率,插件下载时间有问题,一定程度上2:渠道商合作的要求,这个要求只在app内,如果插件不受其影响,APP体积越大,渠道商的成本就越高,比如要求ROM空间越大,安装时间越长,这些都极大地影响了手机的用户体验。3:同时,更大的包体积,无论是插件还是app,也意味着更长的安装时间和更长的oat时间(安卓系统9之前,安装会自动转成oat)。本文所依赖的知识点包括Gradle插件编译过程、Gradle插件编写、Groovy、Android打包过程、AndroidAAPT过程等,全文4221字,预计阅读时间12分钟。一、apk包的组成Android安装包由很多部分组成,主要如下:代码相关:class.dex动态库(SO)相关:lib资源相关resource.arscres/,assetsMETA-INF存放签名和其他信息通过以上封装体积的成分不难分析。控制apk的打包体积,就要控制dex、动态库、资源数据。动态库(SO)可以动态下载,也可以按需下载;其次,只有dex和resources,dex就是我们下一篇要讲的内容。这部电影主要讲的是资源优化。2.资源优化对于图片资源,使用AndroidSizeAnalyzer生成资源排序列表。分析出结果后,可以对分析出来的图片进行优化,比如图片压缩,云控资源,webp,矢量图,去除冗余资源等等,以上都是关于单张图片的处理。本文主要讲的是资源的混淆和优化。整个资源混淆的实现是基于AndroidResGuard的二次开发扩展。为什么要二次开发?整个直播基于插件实现,原有工具不支持插件资源混淆;大家都知道,为了解决插件和hosts的resourceid冲突问题,插件需要固定resid的package部分,resourceid的组成如下:[.]R..对于插件//additionalParameters"--package-id","0x61","--allow-reserved-package-id"简单介绍一下资源映射表协议的原理,resources混淆的原理很简单:通过下面的映射关系,将一个复杂的字符串转换成一个短字符串,从而减小资源映射表的字符串常量池的大小。下图是混淆前后的对比。一旦加上packageid,整个资源混乱就会出错。对比资源映射表的二进制和协议,发现扩展packageid时arsc不符合协议。问题所在。以后会找到合适的方案,就是扩展arsc资源映射表协议。从上图可以看出,经过混淆之后,资源映射表的体积大大减小了。3.资源映射表协议从上图分析定位一个资源,先通过资源类型,再通过资源id,通过资源id(ID),找到资源名称(name),再根据mdpi/找到当前机器的land/ldpi,加载不同文件路径下的资源。resources.arsc以Chunk块的形式组织,Chunk的头部信息记录了Chunk的类型、长度等数据。从整体上看,它的结构是资源索引表头+字符串资源池+N包数据块。001Editor下的资源映射表结构如下:4.实施方案的实施包括三部分:方案的设计与实施、QA流水线的配置、单功能版本的灰度.5.方案设计的实施由于是对原项目进行二次开发和扩容,所以需要对原项目的结构有一个清晰的认识,包括每一个细节,包括资源混淆规则,如何映射白名单,并从中梳理出我们的需求包括资源白名单映射、夜间模式、映射表修改、映射表重写。整体代码结构如下图所示,黄色标记为需要二次开发的模块。如上图,一共涉及3个部分的核心工作,包括配置模块、插件模块、核心映射表混淆模块;a:配置模块配置如下参数:mappingFile=file("./resource_mapping.txt")use7zip=falseuseSign=false//打开这个开关,会保留所有资源的原路径,只会混淆theresourcenamekeepRoot=true//设置这个值会将arscname列混淆成相同的名字,减少字符串常量池的大小//fixedResName="arg"//打开这个开关会合并所有同名的资源hash值,但请不要过分依赖这个函数来去除多余的资源]动态配置参数,这个是针对插件唯一的fixid,生成白名单配置列表混淆资源不能混淆,在模块内部数据准备阶段,必须偷偷传给t他Gradle插件//生成修复文件的白名单defgenerateWhiteList(){deffixFile=file("host-res-fix/${rootProject.ext.plugin_fix_file_map[host]}")defresGuard=file("resguard/res_guard_config.xml")defresproguard=newXmlParser().parse(resGuard)defissueNode=newNodeBuilder().issue(id:'whitelist',isactive:true)resproguard.issue[0].replaceNode(issueNode)fixFile.eachLine{line->//TODO白名单行生成}newXmlNodePrinter(newPrintWriter(resGuard)).print(resproguard)returnresGuard}b:资源映射表读写:读取资源映射表的目的是为了形成基本的arsc框架。重新写回arsc,结构可以如下图所示:扩展协议部分是支持插件资源混淆的核心,基本规则是按照扩展协议顺序读写代码片段如下:privatevoidwriteLibraryType()throwsAndrolibException,IOException{mOut.writeInt(libraryCount);for(inti=0;i