.dex文件更小并且拥有更好的运行时性能
包含java 8语言支持的处理
使用方式(AS3.1默认)
gradle.properties
android.enableD8=true
R8
和混淆类似,使用随机无意义的名称
内联,避免对象分配
在删除未使用的类、字段、防范上更好
与相比,R8能使apk减小约10%,体积更小
使用方式
android.enableR8=true
android.enableR8.libraries=true
d、移除无用代码
随着业务增加,许多之前使用的类可能并没有用到,然后又想着以后万一又能用到呢?反正就一个文件,删不删除无所谓,占内存又不大,长此以往,apk就越来越大了。
我平时都用 自带的 Lint 检测工具无效代码
慕课网的性能优化视频里讲到过一种方案,通过(简单入门)对某个包下的类就行构造函数切面
@After("execution(org.jay.launchstarter.Task.new(..)")
public void newObject(JoinPoint point) {
LogHelper.i(" new " + point.getTarget().getClass().getSimpleName());
}
感觉这个确实能打印出来使用的类,可以搜集起来,那还得写一个脚本找出没使用得类,删除,有点风险。
我觉得还是提出的方案简单有效,通过 插件 基于线上用户上报无用代码分析
2、资源瘦身
首先我们了解一下APK解压后,资源相关的目录
a、资源混淆
混淆优点
采用方案 微信的
b、无用资源删除
android{
....
buildTypes{
release{
shrinkResources true
minifyEnable true
}
}
}
一般我们都会在build.里面配置上述代码,并通过 自带的Lint检测工具 进行 删除无用资源,这里注意,笔者操作过程中,发现用Lint检测出来的无用资源,很多其实都引用了的。
注意,这里配置 true 是真的将无用资源去除了吗?答案:不是的
理由有两点
综上,所以说系统目前的这种做法并没有真正减少文件数量,.arsc、签名信息、以及ZIP文件信息依然没有改善。
为什么系统不做删除呢?因为.arsc和R文件的资源ID默认是连续的,删除无用资源文件,资源ID会改变,这个时候代码中已经替换过的ID就会出现资源找不到的情况,所以只是替换成了空文件。
思路方案:删除文件,同时keep住R文件和.arsc中的ID
还有一种,利用 - 分析,具体可以查看
c、图片压缩
这个比较好实现,笔者将项目中大于10k的图片都压缩了一下,体积减小了3%,笔记使用了cwebp 工具,转换成webp
# coding=utf-8
import os
from pathlib import Path
'''
file_directory : 目录
modules : 变长参数 指定模块才解析
'''
def findAndConvert(file_directory, *modules):
if len(modules) == 0:
print("modules must Designated")
return
if file_directory.is_file():
print("this is a file , need a directory")
return
if os.path.exists(file_directory):
print("has this directory")
for homes, dirs, files in os.walk(file_directory):
# print(homes)
# print(dirs)
# print(files)
for module in list(modules):
check_path = os.path.join(file_directory.absolute(), module)
if check_path in homes:
# print("============== convert this path " + check_path + " ================== ")
# 寻找 src/main/res/darwable开头的文件
# 或者直接找png jpg图片
if "src\\main\\res" in homes and "drawable" in homes:
# print(homes)
for file in files:
if file.endswith(".png") or file.endswith(".jpg"):
file_path = Path(os.path.join(homes, file))
if file_path.is_file() and os.path.getsize(file_path.absolute()) > 10 * 1024:
# print(file)
# print(file[:-4])
current_file = os.path.join(homes, file)
target_file = os.path.join(homes, file[:-4] + ".webp")
cmd = "cwebp " + current_file + " -o " + target_file
result = os.system(cmd)
if result == 0:
# os.remove(file_path.absolute())
os.system("svn add " + target_file)
os.system("svn del " + current_file)
# else:
# print("please check this path " + check_path)
else:
print("this directory has not exists")
if __name__ == '__main__':
path = Path("D:/WorkSVN/项目Prject/")
# 指定包名 变长参数必填
findAndConvert(path, "模块名","模块名2")
d、资源文件规范化
3、SO瘦身
这个不多说了,直接上代码
defaultConfig {
ndk {
abiFilters "armeabi"
}
}
现在市面上大多都是架构,例如,微信APK分析一下,也能发现只有,虽然微信对加载做了CPU 架构的适配,什么时候加载的哪个so文件,都有适配。
详细可以了解 为何大厂APP如微信、支付宝、淘宝、手Q等只适配了-v7a/?
这里给出一个abi工作规则图
从图中可以得出另一个规则
三、进阶瘦身方案1、代码瘦身
a、三方库处理
其实这个都不能算做进阶瘦身方案,但在实际操作中,我确实没有想到对三方库进行处理,导致没必要的依赖加载进来的,毕竟将所有模块代码看一遍,很多模块不是自己写的,优化起来丢三落四的,所以放到进阶方案里了。
在选择第三方库时,需要评审一下,以性能为第一指标,包体积为第二指标,尽量选择性能好,体积小的第三方SDK,并且在使用到第三方SDK某个功能时,尽量继承某个功能依赖,而不是全部,例如只需要的某个webp功能,那就只集成webp依赖就好了。
我按照方案,将项目里所有依赖都过了一遍,发现图片相关Glide和都使用了,GG,并不能选择一个用,改动太大,涉及测试也很多,只能将这种方案在组内会议规范一下。(PS:加载长图会显示空白的)
b、去除debug信息与行号信息
dex文件结构图(摘自极客时间开发高手课包体积优化)
一般,我们都会在混淆配置中以下面的方式保留行号信息
-keepattributes SourceFile, LineNumberTable
如果不保留行号信息,dex大约可以减少5%的体积,但是Crash上报后,会拿不到行号怎么办?问题该怎么定位?同学,莫慌,支付宝 包大小极致压缩方案 帮你解决。
当然,支付宝这个方案是参考的的 ReDex ,这个只支持linux、和mac。因为我之前了解过ReDex,所以在接到压缩体积包时,也调研过,可是编译阶段硬是没有编译过去,后面试了两次,还是有点问题,就没有使用该方案。
ReDex 有六个优点
c、Dex分包优化
上面讲到了ReDex的一个优点,基于反馈的Class字节码布局,这是啥意思呢?
类字节码在单个 Dex 中的布局是根据编译顺序而不是运行时行为决定,即便 会将 App 定义的组件以及部分启动需要的类放在 Main Dex 中,但依然不是根据运行时顺序布局,这会导致程序启动时需要查找随机分布在 Dex 中的类。
ReDex 会将 APK 在 Lab 中试运行,并跟踪启动时哪些类需要加载,然后将这些类字节码放到 Dex 前部,减少启动时从闪存中寻找类的时间,从而提高 App 启动速度。
好的,大致了解了,那你可能会问,这个跟Dex分包优化有半毛钱关系?
在我们使用分包后,此时的每一个Dex可能会调用到其它的Dex中的方法,这种跨Dex调用的方式会造成许多冗余信息,具体有两点
为了保证Dex有效率在80%以上,通过以下公式来衡量优化效果
Dex 信息有效率 = define methods数量 / reference methods 数量
为了实现上述所说的信息冗余去除,ReDex配置一下就可以
{
"redex" : {
"passes" : [
"InterDexPass",
"RegAllocPass"
]
},
"InterDexPass" : {
"minimize_cross_dex_refs": true,
"minimize_cross_dex_refs_method_ref_weight": 100,
"minimize_cross_dex_refs_field_ref_weight": 90,
"minimize_cross_dex_refs_type_ref_weight": 100,
"minimize_cross_dex_refs_string_ref_weight": 90
},
"RegAllocPass" : {
"live_range_splitting": false
},
"string_sort_mode" : "class_order",
"bytecode_sort_mode" : "class_order"
}
d、Dex压缩
你可以分析一下 APP的dex文件,他把真正的代码放到了下面,导致只有一个700多kb的.dex,他通过XZ Utils将所有dex压缩成了一个。
XZ 压缩算法 和 7-Zip 一样,内部使用的都是 LZMA 算法。对于 Dex 格式来说,XZ 的压缩率可以比 Zip 高 30% 左右。但是这套方案存在一些问题
上面的讲解摘自极客时间开发高手课,这里仅当了解了一下,因为还需要分版本适配,臣妾做不到,难度对于目前的我来说很高。
2、资源瘦身
真正去除无用资源
利用 - 分析,具体可以查看
重复资源优化
这个在项目开始时就需要制定好规范,但是也避免不了,多个地方用到的图片或资源存放在不同的模块下,毕竟这是团队开发。这个问题在任务开展过程中,确实不好搞,因为存在太多相同字符串,名称不同,文案一样,然后图片又有相同的,命名又不一样,难搞。
具体实施方案查看
3、SO瘦身
a、对的压缩与合并、裁剪
跟Dex一样,可以通过XZ Utils压缩
在默认的lib目录中,我们只需要加载少数启动过程相关的 ,其它放在首次启动时解压。对于压缩率来说,可以比ZIP压缩高30%,效果很好。缺点和Dex类似
实施方案,配合采用的一个开源库
合并
在 4.3 之前,进程加载的数量是由限制的,可以点击查看
然后又出来方案了 和 Demo
裁剪
又是的方案
原理:分析代码中的JNI方法以及不同方法调用,找到没有无用的导出,然后删除掉,这样在编译的时候也会把对应的无用代码同时删除掉。
四、长效治理APK包体积
笔记一完结
42岁郝蕾,3个月瘦35斤,3个“懒人减肥技巧”,简单、实用,郝蕾,减肥,瘦身,减肥方法,瘦腰,瘦腿
记者 | 张倩楠 编辑 | 翟瑞民1 国家发改委日前正式发布《“十四五”新型城镇...
去年听同事说麦吉减肥法见效特别快,所以试了下,瘦了18斤,开开心心吃了一年,今年又开始了,分享给大家,也防止自己丢失。 麦吉减肥法一、科学原理 当饮...
让上海公交25路女司机蔡筱瑾没想到的是,开了28年“辫子车”的她,竟然在临退休前的一个多月,没有了车顶上的“牵绊”。_新浪网...
不得不说李佳琦绝对有些玄学在身上,在我犹豫要不要用白芸豆减肥的时候,网上已经有他推荐的那个白芸豆传说了! 经过我2个月的使用,得出结论:这个白芸...