找回密码
 会员注册
查看: 9|回复: 0

Android包体积优化上篇-资源混淆优化

[复制链接]

5

主题

0

回帖

16

积分

新手上路

积分
16
发表于 2024-10-5 18:24:29 | 显示全部楼层 |阅读模式
导读:什么时候进行包体积优化?一般在app初创期时,由于业务代码较少,包体积也不大,相应这个时候对包体积的优化收益也较少。当业务逐渐成熟功能,迭代逐渐变多,包体积也会逐渐增加。增加包体积主要影响如下几个方面:1: 如果针对app,会影响到下载转化率,但手百内部直播属于插件,所以不存在转化率的问题,存在插件的下载时长问题,进而在一定程度上影响插件冷启首屏;2: 渠道商合作的要求,这个要求只在app里面,如果是插件不受其影响,app的体积越大,渠道商的资费会更高,如要求更大的ROM空间,更长的安装时间,这些都极大影响手机已经用户体验。3: 同时更大的包体积,不管是插件还是app,也意味着更长的安装时间,更长的oat时间(Android系统9之前,安装会自动转换为oat)。本文章依赖的知识点有Gradle插件编译流程、Gradle插件编写、Groovy、 Android打包流程、Android AAPT流程等。全文4221字,预计阅读时间12分钟。一、apk包的组成Android安装包是由很多部分组成的,主要有如下:代码相关:class.dex动态库(SO)相关:lib资源相关 resource.arsc res/,?assetsMETA-INF 存放签名等信息通过以上包体积的组成部分,不难分析,要想控制apk的包体积,需要在dex、动态库、资源数据上进行控制。动态库(SO)可通过动态下载、按需下载的方式;其次只有dex和资源,dex是我们下一篇里面要讲的东西,本片主要讲资源的优化。二、资源优化针对图片资源,使用Android Size Analyzer 可生成资源的排序列表,通过分析后生成结果,可对分析后的图片采取优化手段,如图片压缩、云控资源、webp、矢量图、移除冗余资源等,以上所有这些都是关于单张图片的处理,本篇主要谈资源的混淆优化,整个资源混淆的实现是基于AndroidResGuard做一个二次开发扩展。为什么要做二次开发?整个直播是基于插件实现,原工具不支持插件资源混淆;大家知道为了解决插件与宿主之间资源id冲突的问题,插件都需要固定器resid 的package 部分, 如下资源id的组成:[ .]R..针对插件//additionalParameters "--package-id", "0x61", "--allow-reserved-package-id"简单介绍下资源映射表协议的原理,资源混淆其原理非常简单:通过如下的映射关系,将复杂的字符串,转换为一个简短的字符串,进而减小资源映射表的字符串常量池的大小。如下图为混淆前和混淆后对比,一旦加入packageid,整个资源混淆会出错,经过对资源映射表二进制以及协议的对比发现,是由于arsc 在进行扩展packageid的时候,与协议不符合导致,问题定位以后,即找到合适的解决办法,即扩展arsc资源映射表协议。?通过上图可以看出混淆后,资源映射表体积大幅度减少。三、资源映射表协议从上图中分析定位一个资源首先通过资源类型,然后通过资源id,通过资源id(ID),找到资源名(name),找到后根据当前机器的mdpi/land/ ldpi,加载不同的文件路径下的资源。resources.arsc是以一个个Chunk块的形式组织的,Chunk的头部信息记录了这个Chunk的类型、长度等数据。从整体上来看,其结构为资源索引表头部+字符串资源池+N个Package数据块。001Editor 下的资源映射表结构如下:四、实施方案的实施包含三部分:方案的设计实现、QA流水线配置、单功能版本灰度。五、方案设计实现由于是在原有工程上做二次开发扩展,需要对原有项目的结构有一个清晰的认识,包括到每一个细节,其中包括资源混淆规则、白名单怎么映射,从中理出我们的需求部分,包括资源白名单映射、夜间模式、映射表修改、映射表重写,整体代码结构如下图,黄标处为需要二次开发涉及的模块。如上图总共涉及到3部分的核心工作,包括配置模块、插件模块、与核心的映射表混淆模块;?a: 配置模块配置如下参数:?mappingFile = file("./resource_mapping.txt") use7zip = false useSign = false // 打开这个开关,会keep住所有资源的原始路径,只混淆资源的名字 keepRoot = true // 设置这个值,会把arsc name列混淆成相同的名字,减少string常量池的大小// fixedResName = "arg" // 打开这个开关会合并所有哈希值相同的资源,但请不要过度依赖这个功能去除去冗余资源 mergeDuplicatedRes = true nightmode_pattern = "_1" // 夜间模式配置 // 基础的sdk都加入白名单, 配合白名单配置文件 whiteList = []动态配置参数,这个是针对插件特有的fixid,生成白名单配置列表混淆资源不能将其混淆,在模块内部数据准备阶段,要将其偷传到Gradle插件内??// 生成fix文件白名单def generateWhiteList() { def fixFile = file("host-res-fix/${rootProject.ext.plugin_fix_file_map[host]}") def resGuard = file("resguard/res_guard_config.xml") def resproguard = new XmlParser().parse(resGuard) def issueNode = new NodeBuilder().issue(id: 'whitelist', isactive: true) resproguard.issue[0].replaceNode (issueNode) fixFile.eachLine { line ->// TODO 白名单行生成 }new XmlNodePrinter(new PrintWriter(resGuard)).print(resproguard)return resGuard}b:资源映射表读写:资源映射表读取的目的是,形成基本的arsc框架,架构形成后,通过映射逻辑将内存数据重新写回到arsc, 可如下图结构:扩展协议部分是支持插件资源混淆的核心,基本规则就是按照扩展协议进行顺序读写即可。代码片段如下:private void writeLibraryType() throws AndrolibException, IOException { checkChunkType(Header.TYPE_LIBRARY);int libraryCount = mIn.readInt(); mOut.writeInt(libraryCount);for (int i = 0; i
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2025-1-11 18:45 , Processed in 0.972404 second(s), 26 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表