【小木箱生长营】功用优化系列文章:
包体积优化 实战论 怎么做包体优化? 做好能提高吗? 能涨多少钱?
包体积优化 办法论 揭开包体优化奥秘面纱
一、引言
Hello,我是小木箱,欢迎来到小木箱生长营系列教程,今天将分享包体积优化东西论初识包体优化。小木箱从两个维度将Android包体优化东西论解说清楚,本文首要说了四个部分内容,榜首部分内容是事务问题和应战。第二部分内容是包体优化根底常识。第三部分内容是代码优化。终究部分内容是总结与展望。
代码优化分为四部分内容,榜首部分内容是代码优化的思路,第二部分内容是7款apk黑盒逆向东西,第三部分内容是7款代码剖析东西,第四部分内容是代码优化注意事项。
假如学完小木箱包体积优化的东西论、办法论和实战论,那么任何人做包体优化都能够拿到成果。

二、事务问题与应战
2.1 为什么要做包体优化
首要咱们聊聊榜首部分内容包体优化面临的事务问题与应战,三个原因解说为什么要做包体优化。

2.1.1 下载转化率
榜首个原因:下载转化率。海外商场上,依据Google Play Store包体积和转化率剖析陈述显现,平均每添加1M,转化率下降0.17%,转化率跟着Apk变大而下降。

国内商场上,华为运用商场流量保护是40M。假如咱们的App体积超越40M,那么在下载时分便有流量装置提示。用户的下载请求被华为运用商场阻拦,用户对App的装置多了一层挑选,用户装置成功率会下降。

2.1.2 途径商要求
第二个原因:许多门户app一般会有一个 Lite版,为什么要求做两款功用相似的运用呢?有两个原因。
榜首, Lite版能够提高app的下载转化率。
第二, 一切app做到必定体量,只要和华为、OPPO、三星、小米等手机厂商进行商务协作,App体积越大,CDN流量费用就越高,途径拓宽就越受限制。 因而,用户下载Lite版能够下降集团本钱。

2.1.3 app功用影响
第三个原因:体积过大对功用负面影响。其间首要表现在三个方面,装置时间和签名校验时间、运转时内存和ROM空间。

2.1.3.1 装置时间和签名校验时间
榜首,装置时间和签名校验时间方面,相同机型和网络环境下,假如包体越大,用户装置时间越久,签名校验的时间越久。


在编译 ODex 期间,Android 5.0 、 6.0 体系,跟着包体增大,消耗时间越久。Android 7.0以后由于混合编译,装置时长方差不如Android5.0、6.0体系大。

2.1.3.2 运转时内存
第二,运转时内存方面,apk的Resource 资源、Library 以及 Dex 类加载会占用运用一部分内存。假如apk体积越大,运转时内存占用越大,那么功用越差。

2.1.3.3 ROM 空间
第三, ROM 空间方面,假如运用的装置包巨细为 50MB,那么发动解压之后必定会超越50MB。

假如闪存空间缺少,很或许呈现“写入放大”的状况,它是闪存和固态硬盘(SSD)中一种不良的现象。

闪存在可从头写入数据前有必要先擦除,而擦除操作的粒度与写入操作比较低得多,履行操作就会屡次移动(或改写)用户数据和元数据。
因而,要改写数据,就需求读取闪存某些已运用的部分,更新它们,并写入到新的方位,假如新方位在之前已被运用过,还需连同先擦除;
由于闪存工作办法,有必要擦除改写的闪存部分比新数据实践需求的大得多。即终究或许导致实践写入的物理资料量是写入资料量的多倍。

2.2 包体优化功用指标
因而,依据下载转化率、途径商要求和体积过大对app功用等诸多事务布景,咱们期望能经过包体优化,达到下降流量本钱,防止由于包体过大导致用户流失的意图。包体优化功用指标也便是咱们上文说到的打包后装置包巨细和装置包装置速度。
三、 包体优化根底
3.1 Apk结构
紧接着来到咱们的第二部分内容,代码优化,了解代码优化之前,首要,咱们先了解下apk文件中都包括了什么。解压apk包,咱们能看到apk全体目录结构如下:

Apk的构成首要分为五个部分。
榜首部分是Dex,首要是class data 源码文件。
第二部分是Resource文件,首要是图片、xml、string等资源文件。
第三部分是Assets文件,首要寄存一些相似签名摘要、音频、html默许文件等。
终究一部分是Native Library文件,首要是C++编写的so,其间lib下寄存不同架构的so库。

影响包体积首要有lib、assets和META-INF文件夹里的文件以及*.Dex 、 resources.arsc文件。

上述五个影响包体积的目录和文件具体内容能够参阅下面表格
目录/文件 | 内容 |
---|---|
lib/ | so文件目录,或许会有armeabi、armeabi-v7a、arm64-v8a、x86、x86_64、mips,大多数状况下只需求支撑armabi与x86的架构即可,假如非必需,能够考虑拿掉x86的部分 |
assets/ | 包括运用的资源;运用能够运用 AssetManager 对象检索资源。 |
META-INF/ | 包括 CERT.SF 和 CERT.RSA 签名文件,以及 MANIFEST.MF 清单文件。 |
*.Dex | Dalvik/ART 虚拟机可了解的 Dex 文件格局编译的类。 |
resources.arsc | 包括已编译的资源。此文件包括 res/values/ 文件夹的一切装备中的 XML 内容。打包东西会提取此 XML 内容,将其编译为二进制文件办法,并将相应内容进行归档。此内容包括言语字符串和款式,以及未直接包括在 resources.arsc 文件中的内容(例如布局文件和图片)的路径。 |
3.2 Apk打包流程
剖析优化计划之前,咱们首要要了解APK打包流程。由于教程面向企业级技术计划而非面试经历贴,APK编译流程参阅官网不做太深化讲解,给咱们整理了两张官方的截图。


总结下来就三句话:首要用aapt打包资源文件, 生成R.java类(资源索引表)、.arsc资源文件 和res文件。

其次生成src资源文件编译产品,aidl files编译生成成java接口,并将R.java文件、工程源码文件、aidl.java文件, 经过javac合成.class文件。

终究.class文件、第三方jar和library,经过dx东西打包成Dex文件,终究是apk签名和apk对齐流程。apk签名和对齐流程咱们能够参阅 yanlong107 的APK编译流程这篇博客。

当然,假如同学们想更深化的了解编译产品表结构,那么咱们在B站看一下马士兵的深化了解java虚拟机和唐朔飞核算机组成原理的免费课程也是能够的。毕竟不断被前端吞噬的移动端商场,假如客户端在Android逆向或Framework斗角场差异化竞争,那么或许更能连续工作生命周期(题外话~)。


3.3 Apk装置流程
传送门: www.jianshu.com/u/9ba051096…
Apk打包流程咱们说完了,接下来咱们说一下Apk的装置流程,Apk的装置流程首要讲解四个部分,榜首个部分是Apk的装置办法.第二个部分是Apk装置进程,第三个部分是装置后文件地点目录,终究一个部分是卸载进程.
3.3.1 Apk装置办法
首要咱们先来说一下榜首部分内容,Apk的装置办法.Android Apk的装置办法首要分为四种,榜首种是体系程序装置,比方: 时钟,日历,设置等程序.一般由ROM厂商更新推送.第二种是经过Android商场装置,Google Play选用Android商场办法进行装置.第三种是ADB装置,假如运用开发云真机布置Debug包,那么通常选用ADB装置办法. 终究一种是手机自带装置办法,假如想运用未发布运用商店的运用,那么咱们能够选用手机自带装置办法.咱们重视来说一下第二种,adb装置,履行adb install指令即可。
3.3.2 Apk装置进程
然后咱们先来说一下第二部分内容,Apk装置进程装置进程.首要仿制Apk装置包到/data/app/pkg目录下.然后解压并扫描装置包,把dex文件(Dalvilk字节码)保存到/data/dalvik-cache目录.其三在/data/data目录创立对应的运用数据目录.其四dexopt履行运用数据目录并注册四大组件.终究,装置完成后,向手机发送装置成功的播送.

3.3.3 Apk装置后文件地点目录
接着咱们先来说一下第三部分内容,Apk装置后文件地点目录。假如装置的是体系自带的运用程序,那么app是装置在/system/app目录下,假如想要删去运用,那么需求获取adb root权限才行。
假如装置的不是体系自带的运用程序,那么app和用户数据首要寄存在/data/app、/data/data和/data/davilk-cache三个目录下。其间,/data/app首要是用户程序装置目录,装置时把apk仿制到此目录下。

其间,/data/data首要寄存运用程序的数据。cd到咱们预装载运用包名,用ls指令查看到一些隐私存储文件,咱们需求root权限才干拜访,俗称沙箱。

终究,/data/davilk-cache是将apk中的dex装置在/data/davilk-cache目录下的。

3.3.4 卸载进程
终究,咱们说一下卸载进程。卸载进程首要是删去装置进程中/data/data、 /data/davilk-cache和/data/app下创立的文件及目录。
3.4 Dex简析
Apk装置流程咱们说完了,打包进程有一个很重要的中间产品Dex,Dex 是Android 体系的可履行文件,包括运用程序的悉数操作指令以及运转时数据。
由于Dalvik是一种针对嵌入式设备而特别设计的 Java 虚拟机,所以 Dex 文件与标准的 Class 文件在结构设计上有着本质的区别。
当Java程序被编译成class文件之后,还需求运用 dx 东西将一切的class文件整合到一个 Dex 文件中。
Dex 文件就将原来每个 class 文件中都有的共有信息合成了一体,意图是确保其间的每个类都能够共享数据。
这在必定程度上下降了信息冗余,一起也使得文件结构愈加紧凑。与传统 jar 文件比较,Dex 文件的巨细能够缩减 50% 左右。
Dex 文件生成流程咱们能够参阅下面的图片:

听到这里,同学们或许会觉得坐而论道,枯燥乏味。乃至或许置疑小木箱是从哪个博主抄的八股文。因而,为了更好学习Dex,小木箱引荐一个能够解析 Dex 文件的东西 010 Editor。010 Editor能够经过预置的模板让咱们更明晰的了解 Dex 文件的格局, 具体运用办法参阅B站视频【Android逆向】Dex文件结构详解(脱壳必学)。

由于篇幅原因,想更多了解关于Dex常识,欢迎移步路遥在路上的Android逆向笔记 —— Dex 文件格局解析和有赞的浅谈Dex进行学习。
3.5 Dex && Jar比较
关于Dex和Jar有些同学会误解两者无必然联系,jar是Java Archive缩写,中文翻译为java二进制归档文件,能够了解为多个.class文件打包的文件。而Dex是直接将.class优化打包后的文件,dalvik虚拟机是.Dex可履行文件
下面是.jar和.Dex的结构体,在逆向开发里边为了更清楚解析他们的文件格局,咱们常常用dex2jar和dx进行互转。
# 装置jd-gui开发者东西
1. d2j-dex2jar.sh 抖音.apk/classes.Dex
# Dex2jar 抖音.apk/classes.Dex -> ./classes-Dex2jar.jar
2. java -jar jd-gui-1.6.6-min.jar ./classes-Dex2jar.jar

假如对逆向方向感兴趣,同学们能够经过传送门到看雪论坛更深化的学习。
四、代码优化
4.2.1 代码优化思路
说完Apk的结构,咱们来到第二部分内容,即代码优化。代码优化分为五部分内容。榜首部分内容是代码混杂。第二部分内容是除掉无用、重复的SDK、精简SDK、树立SDK接入标准。第三部分内容是除掉无用的代码,优化重复的代码。第四部分内容是Dex紧缩。第五部分内容是多Dex相关优化等环节。
A 代码混杂
榜首部分内容,代码混杂给咱们引荐Proguard ,Proguard 是一个很强悍的东西,Proguard 能够帮你在代码编译时对代码进行混杂,优化和紧缩。后文会具体解说Proguard 运用办法。能够经过classShark.jar和python 脚本自动生成混杂文件。
B 除掉Unused代码、除掉重复的SDK、精简SDK和引进SDK接入长效管理机制
第二部分内容除掉Unused代码,操作办法也很简单,点击AS左上角导航栏Refactor的Remove Unused Resources即可,可是注意不要除掉换肤的图片。

当然跟着事务需求的不断迭代,有些SDK或许是非必要的,咱们承认好事务需求后利用**dependency-analysis-android-gradle-plugin** 插件除掉无用或重复的SDK。

但,项目中或许多个当地用到了相似功用的第三方库,比方相似ImagLoader和Glide、Recyclerview和BRGV、Sp和MMKV等等意图相同,但完成办法不相同。

经过了一次次迭代后,或许会构成前史包袱,不要轻易重组合并。包体优化不能雪中送炭,锦上添花罢了,优化前提是确保中心事务稳定性。假如影响到原有的中心事务,那么就得不偿失。
为了防止呈现边管理边污染的状况,树立SDK接入走审阅、不符合包巨细规定需求走请求长效管理机制势在必行。
C 除掉无用的代码,优化重复的代码
第三部分内容是除掉无用的代码,优化重复的代码。删去无用代码是指当在mainfest 清单里边的activity注册四大组件时分,并不会被Proguard 混杂影响,所以,有承认不需求的功用,咱们需求把对应代码整理掉。

优化重复的代码是指跟着事务的不断迭代,有些功用实践是不可用的,但事务代码沉积在工程里边,所以咱们有必要及时对无用的事务进行整理。
D Dex减肥
第四部分内容是Dex减肥,咱们都知道一旦Dex 的办法数就会超越65536个,就有必要选用 mutildex 进行分包。可是此时每一个 Dex 或许会调用到其它 Dex 中的办法,这种 跨 Dex 调用的办法会造成许多冗余信息。冗余信息分为两种,
榜首种是剩余的 method id,跨 Dex 调用会导致当时dex保留被调用dex中的办法id,冗余会导致每一个dex中能够寄存的class变少,终究又会导致编译出来的dex数量增多,而dex数据的添加又会进一步加剧这个问题。
第二种是其它跨dex调用造成的信息冗余,除了需求多记载被调用的method id之外,还需多记载其所属类和当时办法的定义信息,这会造成 string_ids、type_ids、proto_ids 这几部分信息的冗余。
因而,为了削减跨 Dex 调用的状况,咱们有必要尽量将有调用联系的类和办法分配到同一个 Dex 中。可是各个类相互之间的调用联系是非常复杂的,所以很难做到最优的状况。
所幸的是,ReDex 的 CrossDexDefMinimizer 类剖析了类之间的调用联系,并 运用了贪心算法去核算部分的最优解(编译作用和dex优化作用之间的某一个平衡点)。运用 “InterDexPass” 装备项能够把相互引证的类尽量放在同个 Dex,添加类的 pre-verify,以此提高运用的冷发动速度。
ReDex有5个功用,Interdex模块首要是类重排和文件重排、Dex 分包优化。其间对于类重排和文件重排,Google 在 Android 8.0 的时分引进了 Dexlayout,它是一个用于剖析 dex 文件,并依据装备文件对其进行从头排序的库。
与 ReDex 相似,Dexlayout 经过将经常一起拜访的部分 dex 文件集中在一起,程序能够因改进文件方位从而具有更好的内存拜访模式,以节约 RAM 并缩短发动时间。
不同于ReDex的是它运用了运转时装备信息对 Dex 文件的各个部分进行从头排序。因而,只要在运用运转之后,并在体系空闲保护的时分才会将 dexlayout 集成到 dex2oat 的设备进行编译。
Oatmeal模块首要是直接生成 Odex 文件。
StripDebugInfo模块首要是去除 Dex 中的 Debug 信息。
access-marking 模块首要是删去 Java access 办法。
type-erasure模块首要是类型擦除。

2015年,依据facebook官方描绘,ReDex优化成果比原来小了25%,一起发动速度提高了30%。
2016年11月28日,鹅厂Bugly团队在 ReDex初探与InterDex 一文中引荐咱们运用ReDex,ReDex是经过优化客户端磁盘上的字节码达到Dex文件紧缩 && 优化发动速度双方收益。
2020年5月31日,国内字节跳动团队在抖音Android 包体积优化探究:依据 ReDex 的 Dex 优化落地实践
表述利用 ReDex 在抖音包体积优化方面取得了一些明显的收益,优化也被同步到了其他各大 App 上。在抖音、头条和其他运用上,他们的优化对Apk 体积的缩减普遍达到了 4%以上,对 Dex 体积的缩减则能够达到 8% ~ 10%
然而,灰天鹅事情出来了,2020年6月30日,国内58技术团队卢景在Android字节码优化东西reDex初探一文中表述混杂后的releaseApk,优化体积小于100KB。4.X体系上冷发动速度提高20%左右,5.0+体系上冷发动速度无明显变化。从成果上看,4.X体系上的冷发动优化较为明显。可是线上4.X用户的占比非常少。
感兴趣的同学能够测验一下ReDex在端上收益是正向的仍是反向的。
E 多Dex相关优化
关于多Dex相关优化,2015年06月15日,美团Android Dex自动拆包及动态加载简介 一文中, 提到了经过MultiDex内联R Field来解决R Field过多导致MultiDex 65536的问题,而这一过程对代码减肥能够起到明显的作用。
2022年01月13日,字节跳动抖音Android 包体积优化探究:从 Class 字节码下手精简 Dex 体积一文中提到了ByteX ,文章表明bytex大幅削减了 Dex 包体积,很大地促进了抖音的用户添加,一起也优化了发动时虚拟机对 Dex 加载耗时。
2020年6月1日,字节跳动 开源 | BoostMultiDex:抢救Android Dalvik 机型 APP 晋级装置体会一文用数据办法说明晰BoostMultiDex比较MultiDex而言,在装置速度上有更优的体会。

F 防止运用枚举
第六部分内容是防止运用枚举,Google官方的Remove Enumerations 和 Android中代替枚举的@IntDef用法,运用注解的办法替换代替枚举类,每削减一个ENUM可削减大约 1.0 到 1.4 KB的巨细;运用办法参阅下图:

G 削减模板代码
第七部分内容是削减模板代码,由于前史包袱问题,Databinding、ViewBinding、ButterKnife自动生成模板代码,导致增大了class 代码体量,因而,Apk变得更大。咱们要尽量防止运用相似依赖注入结构。
H 代码库精简
第八部分内容是代码库精简,Android Support V4 包的精简能够经过下载其间的jar包来进行删去,但Android Support V7 包则需求削减代码中不必要的引证了,这部分的优化难度比较大,各第三方库,组件化组件等都会引证到support的库,很难进行除掉。可见,Android Support V4 包优化空间还比较大的。
I R8优化
第九部分内容是R8优化,R8 把 desugaring、shrinking、obfuscating、optimizing 和 dexing 都合并到一步进行履行,并且,R8会对代码进行一系列的优化操作以删去更多未运用的代码,
假如R8检测到从不运用给定if-else语句的 else 分支,则R8将删去 else 分支的代码,假如咱们的代码仅在一个当地调用办法,R8或许会删去该办法并在单个调用方位内联它。
假如R8确定一个类只要一个唯一的子类,并且该类自身未实例化(例如,一个抽象基类仅由一个具体的完成类运用),那么R8能够组合这两个类并从app中删去一个类。
R8会删去无引证办法,经过R8编译生成的dex办法数会明显削减。
终究,时间坚持良好的编程习气,去除重复或者不必的代码,慎用第三方库,选用体积小的第三方SDK
J Dex分包
第十部分内容是Dex分包,ReDex 的 CrossDexDefMinimizer 类剖析了类间的调用联系,运用了贪心算法去核算部分的最优解。
运用 “InterDexPass” 装备项能够把相互引证的类尽量放在同个 Dex,添加类的 pre-verify,以此提高运用的冷发动速度。在 ReDex 中运用 Dex 分包优化跨 dex 调用造成的信息冗余的装备代码如下所示
{
"redex" : {
"passes" : [
"InterDexPass",
"RegAllocPass"
]
},
"InterDexPass" : {
"minimize_cross_dex_refs": true,
"minimize_cross_dex_refs_method_ref_weight": 33,
"minimize_cross_dex_refs_field_ref_weight": 44,
"minimize_cross_dex_refs_type_ref_weight": 55,
"minimize_cross_dex_refs_string_ref_weight": 66
},
"RegAllocPass" : {
"live_range_splitting": false
},
"string_sort_mode" : "class_order",
"bytecode_sort_mode" : "class_order"
}
为了进一步削减 Dex 的数量,让每个 Dex 的办法数不糟蹋,即装满 65536 个办法。衡量优化作用,咱们运用Dex信息有效率进行核算:
Dex 信息有效率 = define methods数量 / reference methods 数量
L 删去Java access办法
为了能供给内部类和其外部类直接拜访对方的私有成员的才能,又不违反封装性要求,Java 编译器在编译进程中自动生成 package 可见性的静态 access$xxx 办法,并且在需求拜访对方私有成员的当地改为调用对应的 access 办法。
2019年8月1日,西瓜技术团队对外发布了西瓜视频 apk 减肥之 Java access 办法删去企业等级技术计划,当然,在 ReDex 中也供给了 access-marking 这个功用去除代码中的 Access 办法。
在开发进程中,需求注意在或许发生 access 办法的状况下,需求恰当调整,比方去掉 private 。 改为 package可见性和运用ASM在编译时删去生成的access办法能够防止发生 access 办法。
在 ReDex 还有 type-erasure 的功用,type-erasure与access-marking 的优化作用相同,不只能削减包巨细,也能提高 App 的发动速度。
4.2.2 7款apk黑盒逆向东西
4.2.2.1 Google Apk Analyzer
传送门: developer.android.com/studio/debu…
榜首款apk逆向东西是来自Google的apk analyzer,只要装置Android开发东西AS即可上手,榜首张图是Apk的文件内存占比信息。

第二张图是Dex文件信息查看

第三张图是Apk文件之间的比照

Apk Analyzer有Google AS自带Buff的优势,无需下载任何插件,下风是对混杂过的app进行源码阅读比较鸡肋。 接下来,小木箱从看雪论坛开源东西链挑选七款不错的apk剖析东西。
4.2.2.2 ApkTool
传送门: bitbucket.org/iBotPeaches…

榜首款逆向东西是apktool,假如直接解压.apk文件,xml文件翻开是乱码的,apktool优势是能够用来提取xml文件、AndroidManifest.xml和图片等资源文件, 下风是反编译的app代码是smail格局,可读性为0,需求凭借其他东西进行查看。

ApkTool东西翻开办法:
cp apktool.jar apktool /usr/local/bin
cd /usr/local/bin && chmod +x apktool.jar apktool
apktool d 抖音.apk

4.2.2.3 Dex-tools
第二款逆向东西是Dex-tools,Dex-tools(曾经叫Dex2jar),能够将Dex格局与Jar文件相互转化,当然也要借用JAVA反编译东西 jd-gui查看JAVA源码。
Dex-tools东西翻开办法:
# 榜首步:解压抖音
# 第二步:将Dex转化成jar文件
d2j-dex2jar.sh classes.Dex
# 第三步:发动JD-GUI查看源码
java -jar jd-gui-1.6.6-min.jar ./classes-dex2jar.jar

4.2.2.4 JADX
传送门: bbs.pediy.com/thread-2598…
第三款逆向东西是JADX,JADX 是一个集成化的反编译开发东西,还能够将源文件导出为 Android Gradle 项目。
JADX GUI东西翻开办法:
java -jar jadx-gui-1.4.5.jar

- JADX有以下7个优势:
- 反编译输出 Java 代码
- 查看源码时直接显现资源称号,而不是像jd-gui里显现的资源ID
- 导出 Gradle 工程
- 支撑.dex, .apk, .jar or .class
- 反混杂
- 支撑代码跳转
- 支撑搜索文本,类
- JADX有以下2个下风:
- 资源文件或许有缺失,资源文件仍是经过apktool来获取
- 在反编译较大的apk时,假如遇到jadx-jui卡顿和假死的状况,可恰当优化jvm相关参数
4.2.2.5 Nimbledroid
传送门: nimbledroid.com/
第四款逆向东西是Nimbledroid,Nimbledroid 是美国哥伦比亚大学的博士创业团队研制出来的剖析Android App 功用指标的体系,剖析的办法有静态和动态两种
静态剖析能够剖分出APK装置包中大文件排行榜,Dex 办法数和知名第三方 SDK 的办法数及占代码全体的比例。
动态剖析能够给出冷发动时间, 列出 Block UI 的具体办法, 内存占用, 以及 Hot Methods, 从剖析陈述中, 能够定位出具体的优化点。
Nimbledroid有两方面优势,榜首经过请求装备api key,可持续集成到完好的ci/cd工业化渠道。第二Nimbledroid免费且接入本钱不高,适合研制人力投入低的小规模事务团队。
当然Nimbledroid也有两方面下风,榜首Nimbledroid的gradle插件与Jenkins 集成进程中,对Nimbledroid团队长时间高保护提出了更苛刻要求。第二Nimbledroid对合规解析数据结构体短少可调用的接口。
下面咱们看一下Nimbledroid Prd设计
4.2.2.5.1 Apk文件巨细排行榜

4.2.2.5.2 Tinypng自动化处理

4.2.2.5.2 Block UI的具体办法名

4.2.2.5.3 办法数陈述

4.2.2.5.4 冷发动剖析陈述
优化前成果


优化后成果


4.2.2.6 Android-classyshark
传送门: github.com/google/andr…
第五款逆向东西是android-classyshark ,android-classyshark是一个面向Android 开发人员的独立二进制查看东西,android-classshark能够阅读任何的Android 可履行文件,并且查看出信息,代码紧缩。比方类的接口、成员变量等等,此外,android-classshark还能够支撑多种格局,比方说Apk、Jar、Class、So 以及一切的Android 二进制文件如清单文件等等。
招集ClassyShark.jar文件,履行下面的指令咱们就能够呼唤咱们的Classy鲨鱼了。
java -jar ~/ClassyShark.jar -open ~/抖音.apk
java -jar Classyshark.jar -export ~/抖音.apk

挑选android-classyshark左上角classes标签能够对类文件进行调查,咱们看到抖音有21个Dex文件。

挑选android-classyshark左上角第二个Method Count标签,能够切换到以包为视图的饼图界面,下图为抖音三方库如leakcanary、okio、retrofit、bytedance等对应的代码结构和类文件信息,抖音共由34个类组成,办法数为1018068个:

经过android-classyshark剖析App的项目结构和引证库的信息,不光协助咱们大致掌握了解项目架构,并且经过调查一流企业正在运用的开源库也协助中小企业学习竞品企业优质代码,突破行业技术壁垒。
4.2.2.7 Ida64
传送门: hex-rays.com/ida-free/#d…
第五款逆向东西Ida64,俗话说,工欲善其事,必先利其器,在二进制安全的学习中,运用东西检测so漏洞尤为重要,而IDA又是玩二进制的神器。有C++根底能够玩转一下。更方便调查so库版别的稳定性去依据事务需求引进工程

4.2.3 7款代码剖析东西
在CI流水线没有打通FireLine之前,除掉无用代码或重复代码,需求代码剖析东西进行人肉查看。下面咱们来说一下7款代码剖析东西。
4.2.3.1 Proguard
榜首款代码剖析东西是Proguard, Proguard有两方面优势,安全方面,Proguard添加了代码被反编译的难度,必定程度上确保代码的安全。
其间, 代码混杂有三种办法:榜首种办法是将代码中的各个元素,比方类、函数、变量的姓名改动成无意义的姓名。例如将 downloadButton转化成字母 a。这样,逆向开发者反编译代码的时分,无法经过姓名猜想用途。

第二种办法是重写代码部分逻辑。将它变成功用上等价,可是又难以了解的办法。比方它会改动循环的指令、结构体。

第三种办法是打乱代码的格局。比方多加一些空格或除掉空格,或者将一行代码写成多行,将多行代码改成一行。

Proguard有四个常用的装备文件咱们需求注意一下。
文件名 | 描绘 |
---|---|
dump.txt | APK中一切类文件的内部结构 |
mapping.txt | 供给原始与混杂过的类、办法和字段称号之间的转化,能够经过proguard.obfuscate.MappingReader来解析 |
seeds.txt | 列出未进行混杂的类和成员 |
usage.txt | 列出从APK移除的代码 |
混杂之后,能够发现有一个 seeds.txt 文件,列出未进行混杂的类和成员,咱们不只能够看到没有被混杂的字段、类、办法并且也能够看到应该被混杂但未被混杂字段、类、办法。
别的一个usage.txt 文件,能够看到从APK移除的代码,相当于代码是不需求的。咱们依据usage做优化,能够直接手动删掉usage.txt文件里应该被移除的变量、类、办法。
Proguard代码混杂过程一共分为三个过程Shrinking、Optimization和Obfuscation。榜首个过程是Shrinking,Shrinking是紧缩的意思,能够在proguard-rules.pro文件经过装备 -dontshrink 符号挑选敞开/封闭紧缩。
为了以减小运用体积,移除未被运用的类和成员,Proguard默许是敞开紧缩的,并且会在优化动作履行之后再次履行,由于优化后或许会再次露出一些未被运用的类和成员。
第二个过程是Optimization,Optimization是优化的意思,能够在proguard-rules.pro文件经过装备dontoptimize符号挑选敞开/封闭优化。optimizationpasses表明Proguard对代码进行迭代优化的次数,Android一般为5,在字节码等级履行优化,经过这些装备能够让运用运转的更快。
第三个过程是Obfuscation,Obfuscation是混杂的意思,能够在proguard-rules.pro文件经过装备dontobfuscate符号挑选敞开/封闭混杂。Proguard默许敞开混杂,增大反编译难度,类和类成员会被随机命名,除非用优化字节码等规矩进行保护。

减肥方面,Proguard能经过缩短字段名、缩短函数名、缩短类名、丢掉未运用的类文件和字节码深度优化等编译办法,精简Apk包体积。
Proguard的运用也会有一些坑。榜首个是,假如项目初次混杂,或许需求全局扫描一切的类和包名,能够先全量keep,然后再逐包放开混杂。第二个是,没有序列化的内部特点类也需求keep。第三个是,EventBus的java、kotlin的onEvent呈现如下反常
private void <init>0
concurrent.AbstractIdleService$1:
woid<init>(concurrent.AbstractIdleService) public woid executeliava.lang.Runnable)
final svnthetic util.concurrent.AbstractIdleService thisso collectImmutableSortedMultisetFauxverideShim::
public static cogoogle.common.collect.ImoutablesoctedMultiset$Builder builder() publicstaticcomgooglecommon.collect.ImmutableSortedMultisetof(java.lang.Object)
publicstaticcomgooglecommon.collecImmutableSortedMultiset of(java.lang Obiect java.lang.Obiect)
public static colecImmutableSortedMultiset of(iava. lang.0biect.fava. lang.Obiect.iava.lang.Obiect)
public static ImmutablesortedMultiset of(java.langObject ava.lang.object, java. lang, object, iava, lang.Obiect)
public static ImmutablesortedMultiset of(iaa,lang,Obiect,javalang.obiect,iava.lang.obiect,iava, lang.biect, java. lang.Obiect) public static varargs com.gooale.common.collectImmutableSortecMultiset
ofliava,lang,0biect.iava.lang.Obiect.iava.lang.Obiect.iava.lang.0biect,iava. lang,obiect,iava, lang,Obiect iava. lang.Obiecti
publicstatic com.aooglecommoncollectImmutableSortedMultiset copyOf(iav.lang.Obiectll) reflectImutableypeToInstanceMap:
public staticcom.google.comon.reflect.ImmutableTypeToInstanceHap of()
oublicstaticcomoooglecommon.reflect.ImmutableTvoeToInstanceHapSBuitder builder() private void <init>(ImmutableMap)
privatejava.lang.0bjecttrustedGetcom.googlecomonreflect.TypeToken)
syntheticvoid<init>( coectImutabepcomoogle.comonreflect.ImmutableTypeToInstanceMap$1) publicjava.lang.0bject getInstancecom.google.commonreflect.TypeToken) public java.lang.0bject getInstanceljava.lang.Class)
publicjava.lang.0bjectputInstance(cmgoogecommonreflectTypeTokenjava.lang.Object) publicjava.lang.0bject putInstanceliava.lang.Class.java.lang.0biect) io.reactivex.internal.operators.flowable,AbstractFlowablewithUpstrean:
public final org.reactivestreams.Publisher sourcel)
com.akewharton.rxbinding2.view.VienLayoutChangeEventObsevable
public static final int ENV STG public static final int ENV PRE public static final int ENV DEV public static final int ENV GRA public static final int ENV PRD
io.reactivex.internal.operators.flowable.ElowableReduceSeedSingle:
publicvoid<init>(org.reactivestreams.PubisheriavaLang0bject.io.reactivex. functions.BiFunction io.reactivex.internal.schedulers.IoScheduler:
public woid shutdown() public int size()
private static final java.lang.String WORKERTHREAD_NAME PREFIX private static final java.lang.String EVICTOR_THREAD_NAME_PREFIX
WEV NEED AITUE TTUE
4.2.3.2 Gradle Plugin(自定义)
第二款代码剖析东西是Gradle Plugin(自定义),咱们能够自定义Gradle Plugin,在编码进程中,躲避体系Log。这样既能躲避信息走漏风险,图片格局转化,也能恰当削减包体积。自定义Gradle Plugin在扫描合规函数、日志输出等场景非常有用的,关于ASM + Gradle Plugin能够参阅2021年10月20 日,京东零售技术渠道研制张旋发表的ASM在隐私合规扫描中的运用实战
4.2.3.3 Coverage
传送门: github.com/bytedance/B…
第三款代码剖析东西是Coverage 插件, Coverage 插件是字节跳动开源的线上无用代码剖析的东西。
由于代码设计不合理以及keep规矩限制等原因,静态代码查看无法找出一切的无用代码,因而,字节跳动供给的一套动态检测剖析计划。
Coverage 插件会对一切类插装,履行Task时分,将信息上报服务器,假如成批用户上报。定义为用户没用到的类。
抖音其完成已用了Coverage 插件,据了解除掉资源文件以外,抖音有超越 1/6 的类没有被运用,共计3M(dex巨细20M),假如能悉数删去,将削减5%包巨细。
4.2.3.4 Simian
传送门: www.harukizaemon.com/simian/get_…
第四款代码剖析东西是静态剖析东西Simian,Simian是一个可跨渠道运用的重复代码检测东西,能够检测代码片段中除了空格、注释及换行外的内容是否完全一致,支撑的言语Java、C、C++、Groovy和Swift等十几门言语。检测成果很具体,注明晰重复的类文件和方位。
Similarity Analyser 2.6.0 - https://simian.quandarypeak.com
Copyright (c) 2003-2018 Simon Harris. All rights reserved.
Simian is not free unless used solely for non-commercial or evaluation purposes.
{failOnDuplication=true, ignoreCharacterCase=true, ignoreCurlyBraces=true, ignoreIdentifierCase=true, ignoreModifiers=true, ignoreStringCase=true, threshold=6}
Found 6 duplicate lines with fingerprint 2340e9b1e2419bcb5516a5a1d9037271 in the following files:
Between lines 70 and 82 in com/sun/corba/se/PortableActivationIDL/_ServerProxyImplBase.java
Between lines 70 and 82 in com/sun/corba/se/spi/activation/_ServerImplBase.java
Between lines 90 and 102 in org/omg/CosNaming/BindingIteratorPOA.java
Found 6 duplicate lines with fingerprint e94fb8a8017a3d05048dcdfb8bce8dff in the following files:
Between lines 101 and 111 in javax/swing/plaf/synth/SynthOptionPaneUI.java
Between lines 96 and 106 in javax/swing/plaf/synth/SynthMenuBarUI.java
Found 6 duplicate lines with fingerprint 16485a9bd0994dc56f52735c2395a7b2 in the following files:
Between lines 290 and 295 in java/time/zone/ZoneRules.java
Between lines 234 and 239 in java/time/zone/ZoneRules.java
Found 6 duplicate lines with fingerprint 7ca74bcd5707431bd195c0d867f5767e in the following files:
Between lines 380 and 398 in org/omg/DynamicAny/_DynFixedStub.java
Between lines 463 and 481 in org/omg/DynamicAny/_DynSequenceStub.java
...
Found 233 duplicate lines with fingerprint 8bc044fa6e21987c76424535dbc1fe47 in the following files:
Between lines 77 and 377 in javax/swing/plaf/nimbus/TextFieldPainter.java
Between lines 77 and 377 in javax/swing/plaf/nimbus/PasswordFieldPainter.java
Between lines 77 and 377 in javax/swing/plaf/nimbus/FormattedTextFieldPainter.java
Found 382 duplicate lines with fingerprint 922ba26b84cbbf0edfabb0e25189c3b4 in the following files:
Between lines 81 and 482 in com/sun/org/apache/xalan/internal/res/XSLTErrorResources_sv.java
Between lines 81 and 482 in com/sun/org/apache/xalan/internal/res/XSLTErrorResources_es.java
Between lines 81 and 482 in com/sun/org/apache/xalan/internal/res/XSLTErrorResources_fr.java
Between lines 81 and 482 in com/sun/org/apache/xalan/internal/res/XSLTErrorResources.java
Between lines 81 and 482 in com/sun/org/apache/xalan/internal/res/XSLTErrorResources_ko.java
Between lines 81 and 482 in com/sun/org/apache/xalan/internal/res/XSLTErrorResources_zh_CN.java
Between lines 81 and 482 in com/sun/org/apache/xalan/internal/res/XSLTErrorResources_pt_BR.java
Between lines 81 and 482 in com/sun/org/apache/xalan/internal/res/XSLTErrorResources_zh_TW.java
Between lines 81 and 482 in com/sun/org/apache/xalan/internal/res/XSLTErrorResources_de.java
Between lines 81 and 482 in com/sun/org/apache/xalan/internal/res/XSLTErrorResources_it.java
Between lines 81 and 482 in com/sun/org/apache/xalan/internal/res/XSLTErrorResources_ja.java
Found 141070 duplicate lines in 12134 blocks in 2406 files
Processed a total of 775314 significant (2402974 raw) lines in 7714 files
Processing time: 4.818sec
4.2.3.5 PMD
传送门: pmd.sourceforge.io/pmd-5.4.1/u…
第五款代码剖析东西是静态剖析东西PMD,PMD是一个静态源代码剖析器。

PMD能找到常见的编程缺点,如未运用的变量,空的catch块,不必要的对象创立等等。
PMD首要关注Java和Apex,咱们Android开发用 Java 就足够了。其实咱们能够自定义,由于PMD开放了很多协助咱们自定义规矩的API 。
PMD具有许多内置查看(在PMD术语,规矩中),这些查看在规矩参阅中针对每种言语进行了记载。咱们还支撑广泛的API来编写您自己的规矩,您能够运用Java或作为自包括的XPath查询来履行。

PMD优势是在CI/CD持续化布置中能够集成到流水线中。PMD支撑办法也是多样化,Maven、Ant、Gradle和指令行PMD都支撑。下面看一下咱们的检测陈述如下:

4.2.3.6 Lint
传送门: developer.android.com/studio/writ…
第六款代码剖析东西是 Lint,什么是Lint呢?Lint是一种是一种由Google供给的静态代码剖析器,只须在指令行调用 ./gradlew lint,Lint就能帮咱们自动检索无用资源。

Lint在检索完之后,Lint会供给一份具体的Lint剖析陈述,经过Lint剖析陈述。咱们有挑选性的除掉“UnusedResources:Unused resources” 区域下的无用资源即可。

当然实际的企业开发,Lint远远无法满足企业开发的,咱们常常需求自定义定制Lint东西链,自定义定制Lint东西链能够参阅朱利源的Android Lint进行学习。

4.2.3.7 FireLine
传送门: magic.360.cn/zh/index.ht…
第六款代码剖析东西是 FireLine,Fireline是360公司技术委员会牵头,Web渠道部Qtest团队开发的一款免费静态代码剖析东西。首要针对移动端Android产品进行静态代码剖析。其最为杰出的长处便是资源走漏问题的全面检测。一起,前方与360信息安悉数门协作,推出了一系列针对移动端安全漏洞的检测规矩。360前方供给免费运用,扫描速度快,并支撑Android Studio插件,Jenkins插件,Gradle布置等多种集成办法。

前方具有四大类规矩,分别为安全类,内存类,日志类,根底类。
• 安全类:依据360信息安悉数门最权威的SDL专门定制,每一条SDL都有实在的攻击案例
• 内存类:各种资源封闭类问题检测(本次评测的重点)
• 日志类:检测日志输出敏感信息内容的规矩
• 根底类:标准类、代码风格类、复杂度查看规矩

对于Android重复代码检测,FireLine有着出人意料的视觉体会,尽管现在360团队不再保护FireLine,可是Prd设计仍值得每家互联网公司深度学习,期望360能持续做出相似FireLine优异的工业产品。


4.2.4 注意事项
关于代码优化有四点注意事项,榜首点是sdk接入标准,第二点是低代码入侵事务,第三点是SDK去重,终究一点是SDK代码剥离引进。
4.2.4.1 SDK准入准则
咱们先来说榜首点,不要为了某个小功用就随意引进sdk,能够考虑源码接入,小组邮件告诉审阅之后才进行sdk是否接入。
4.2.4.2 低代码入侵事务
然后咱们说说第二点,挑选第三方 SDK 的时分,咱们能够将包巨细作为挑选的指标之一,咱们应该尽或许地挑选那些比较小的库来完成相同的功用。
4.2.4.3 SDK去重
接着咱们说说第三点,不要挑选重复功用的sdk。假如有,能够考虑去掉其他的,比方用了高德地图就不必运用百度地图了。
4.2.4.4 SDK代码剥离引进
终究咱们说说第四点,某些库支撑部分功用别离,不需求引进整个包比方高德地图,假如只运用定位功用,就不要参加map才能了。
五、 总结与展望
本文首要说了三个部分内容,榜首部分内容是事务问题和应战。第二部分内容是包体优化根底常识。第三部分内容是代码优化。代码优化分为四部分内容,榜首部分内容是代码优化的思路,第二部分内容是7款apk黑盒逆向东西,第三部分内容是7款代码剖析东西,终究一部分内容是代码优化注意事项。
近些年来,中大厂门户app不断成熟,功用不断堆积和迭代,Android打包后体积越来越大。装置包体巨细不只对用户留存、商场推广有负面影响,并且假如后续缺少长效管理监管机制,那么包体巨细会呈现边管理边污染的现象。官方引荐、微信、美团、QQ音乐、字节跳动、快手、手淘和蘑菇街等包体优化计划对咱中小企业依然有学习意义。
下一篇办法论会从上而下带咱们揭秘常见包体优化场景。我是小木箱,咱们下一篇见~
优质技术计划参阅
- developer.android.com/topic/perfo…
- developer.android.com/studio/buil…
- www.guardsquare.com/manual/conf…
- 包体积优化(上):如何削减装置包巨细?
- 包体积优化(下):资源优化的进阶实践
- 支付宝 App 构建优化解析:Android 包巨细极致紧缩
- 美团 Android App包减肥优化实践
- 美团 Android 对 so 体积优化的探究与实践
- 字节 抖音 Android 包体积优化探究:从 Class 字节码下手精简 Dex 体积
- 字节 抖音 Android 包体积优化探究:资源二进制格局的极致精简
- 字节 抖音 Android 包体积优化探究:依据 ReDex 的 Dex 优化落地实践
- 货拉拉 Android 包体积优化实践
- 有道词典 Android 客户端包体积优化之路
- 百度 App Android 包体积优化实践(一)总览
- 百度 App Android 包体积优化实践(二)Dex 行号优化
- 百度APP Android包体积优化实践(三)资源优化
- 得物 App 包体积管理之路