很喜欢android size瘦身这个工作,有挑战性,有简单的方法,也有复杂的,还有很多意向不到的地方。感觉去这种任务有一种魔性,去完成这种工作就像去完成一件艺术品。
下面记录一下自己去做size瘦身的种种手段:
要瘦身,首先要分析一下android包内资源大小的分布
一、分析APK的大小
做瘦身之前首先要对apk做一个系统的分析,网上有个工具可以对apk进行详细的分析。、
但是其实一个apk就是一个压缩包,所以个人更喜欢直接直接以zip的形式打开。
一个apk下面有如下的文件:
1、classs.dex //最后打包之后的.class文件的集合。
2.、resources.arsc//最后打包之后的样式集合
3、assets//这个文件夹下面的文件会原装的打包进apk当中,不会做任何的压缩。
4、lib//so库,不多说
5、res//图片,布局等xml的集合
6、META-INF//存储签名的一些信息
个人测试下来,一般
dex文件能够压缩到原来的40%,resources.arsc文件能够压缩到原来的20%。
res文件夹则具体看里面的图片和资源的类型了。不同图片的压缩比是不一样的。一般来说能够压缩到原来的50%以下。
二、瘦身方法
通用方法:
1、对于图片进行瘦身。
分别使用tinkpng和webp对原有的图片进行压缩。对比大小,在不失真的情况下使用小的。由于两者采取的压缩算法是不一样的, 所以有的图片tinkpng压缩后会小一些,有的webp会小一些。另外如果视觉允许的话,可以适当的使用jpg图片。
2、AndResGuard
这是微信开发团队使用的方式。github地址:GitHub - shwenzhang/AndResGuard: proguard resource for Android by wechat team
原理就是利用public.xml中资源id和资源文件名一一对应的关系,对原有的资源文件名进行混淆操作,文件名变得更简单,从而减少字节数。
使用下来确实有效,40M大小的APK能减少1M的大小。
PS:3、4、5本来可以写在一起的,但是为了条目更清晰,还是分开写吧。
3、删除无用文件
Analyze->Run Inspection by Name->Unused resources->
弹出下面的界面:
分别是选择针对整个工程、单个module、或者当前的文件。下面会讲到,如果是Current Directory时就指的是一个目录了。
点击OK开始扫描,结果如下:
然后就可以很愉快的开始删图片和资源了。
但是这里要注意,这里的扫描是以Module为单位的扫描。如果一个资源没有被当前的Module A所使用,但是依赖A的Module B使用了这个资源。扫描一样会提示该资源没有被引用。所以删之前一定要全局查一下。
4、删除无用引用
同样的流程
Analyze->Run Inspection by Name->Unused assignment
扫描结束后会提示一些方法中永远也不会使用到的逻辑或者申明,这时候就可以适当的删掉。而且这里还会递归推算一下。即当前看起来被引用,但是实际引用这个方法的地方永远都不会调用。
来个栗子:
5、删除无用申明
Analyze->Run Inspection by Name->Unused declaration
原理基本上和上面一样。只不过这个是找出来一些没有用过的方法和成员变量。
来个栗子:
经过3/4/5这三步,直接从别的工程拷贝过来的一个1W行代码的模块,减少了大约2000行代码。
6、混淆配置
一定要使用混淆配置,而且要尽可能的小范围的keep类。不要为了图省事直接全部keep掉。一个java类混淆之后的size只有原来的二分之一大小。
拆分依赖的工程。如果有的依赖工程是使用反射找类的,必要的时候直接copy原工程进来,注入原有引用的代码。
独创部分:
PS:独创部分并不是对所有工程都适用的。
另外,下面的关于1/2/3资源检查特意写了一个工程来进行检查,地址:
https://github.com/aa5279aa/AndroidCheck
1、重复styles样式文件扫描。
我们在编写工程的时候,经常会用到什么样式就去现写,而不会去查一下之前是否存在。
比如下面这样的引用:
<TextView android:id="@+id/check_out_title" style="@style/text_12_333333_b" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginRight="5dp" android:layout_toLeftOf="@id/icon_arr" android:gravity="right" android:text="离店" />
这个TextView引用了样式text_12_333333_b
<style name="text_12_333333_b"> <item name="android:textSize">12dip</item> <item name="android:textStyle">bold</item> <item name="android:textColor">#333333</item> </style>
但是同样的文件当中,或者这个module依赖的其它module当中,还有一个一模一样的申明,如下:
<style name="text_checkout_styles"> <item name="android:textSize">12dip</item> <item name="android:textStyle">bold</item> <item name="android:textColor">#333333</item> </style>
这样就造成了styles代码的冗余。
2、相同layout.xml文件扫描。
对于功能类似的layout文件,我们可以分析xml的结构,生成<RelativeLayout>----<TextView>----</TextView>----</RelativeLayout>这样的序列记录。
然后统计下有多少相同的,最后分析下哪些可以合并。
这个在我的AndroidCodeCheck工程里面也有。
3、PBModel的合并
现在PB的序列化都是按照tag顺序来的。也就是说如果两个Model即使定义的不同,但是如果tag顺序一致的话,也是可以合并成一个复用的。
设置即使tag的数量不一致,取多的那一个,也是可以复用的。
优势:减少代码量,并且提高加载速度。预测
劣势:降低了代码的可读性(这个可用增多代码注释来补偿)
可做的点:我们可以写一个脚本来检测所有可以复用的Model。我估算对于那些pb中非reqeust和response的Model,可复用的比例是相当高的。可复用的条件是一个Model包含另一个Model中相同tag的所有信息。
在尽可能的不影响逻辑的前提下,我定义了如下的合并规则:Request和Response合并三个参数(含三个参数)以下的,Model合并四个参数以下的。
统计出来共有16中类型,共有144个Model符合合并条件。
预计可以减少代码行5000行左右。
4、旧的业务逻辑代码下线
很多时候,我们做的功能如果不是用户想要的,是会下线掉的。
但是由于我们编写的时候逻辑不明,导致下线麻烦。
5.字节码层面优化。
同样功能的一个类:
package com.xt.client.function.route;
public class MyRouter {
static boolean aflag;
}
和
package com.xt.client.function.route;
public class MyRouter {
static boolean aflag = false;
}
编译成字节码之后,第一种方式字节码会节省10行。