了解APK结构
-
classes.dex: 代码文件
传统的Java程序,首先先把Java文件编译成class文件,字节码都保存在了class文件中,Java虚拟机可以通过解释执行这些class文件。而Dalvik虚拟机是在Java虚拟机进行了优化,执行的是Dalvik字节码,而这些Dalvik字节码是由Java字节码转换而来,一般情况下,Android应用在打包时通过AndroidSDK中的dx工具将Java字节码转换为Dalvik字节码。
-
assets目录:
用于存放需要打包到APK中的静态文件,这些资源不会被编译成二进制。
-
lib目录:
这里存放应用程序依赖的native库文件。
-
res目录:
这个目录存放资源文件,直接将项目的res目录打包进来。
-
resources.arsc:
用来记录资源文件和资源ID之间的映射关系,用来根据资源ID寻找资源。包括stirng,id,anim,style,mipmap,dimen等类型。
-
META-INF:(签名信息相关)
AndroidSDK在打包APK时会计算APK包中所有文件的完整性,并且把这些完整性保存到META-INF文件夹下,应用程序在安装的时候首先会根据META-INF文件夹校验APK的完整性,这样就可以保证APK中的每一个文件都不能被篡改。META-INF目录下包含的文件有CERT.RSA,CERT.DSA,CERT.SF和MANIFEST.MF,其中CERT.RSA是开发者利用私钥对APK进行签名的签名文件,CERT.SF,MANIFEST.MF记录了文件中文件的SHA-1哈希值。
-
Androidmenifest.xml:
清单配置文件自不必说。
包体分析
1.包体分析主要借助的是腾讯 AppChecker 完成的,AppChecker 分析包文件主要还是借助了 andoid build-tool 下面的 aapt 工具。关于 AppChecker 使用指南可以参考下面的链接:
https://github.com/Tencent/matrix#matrix_android_cn
2.利用应用市场发包情况可以绘制 iOS/Android 的安装包大小变化趋势图。
3.竞品对比
APK 文件大小排行榜可以参考下图,按照大小从上至下进行排序即可。
相似图片监测可能需要使用 AI 技术,重复资源分析用 AppChecker 即可完成目的。
当然无用资源分析也可以用 AppChecker 完成。
压缩Apk具体措施
-
使用混淆、启动资源缩减
在gradle使用minifyEnabled进行Proguard混淆的配置,可大大减小APP大小。
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
-
删除无用资源
从Code->Analyze code ——> Run Inspection by Name进入,输入unused resources。
对整个项目或者某个模块进行未使用资源扫描。
可以看到扫描结果下,没用到的资源,会标明warning,可以选择单个删除还是统一删除。
-
so文件缩减
如果一个app,用c、c++来写功能,打包到so库中使用,性能会比在java层写的代码更高。比如微信的so库的代码比重比价大,微信对性能要求很高。
如果项目中使用到so库,只需要打armeabi-v7a、armeabi-v8a架构,就可以兼容绝大多数cpu类型,这样可以减少apk中lib大小。 现在你可以只打armeabi-v7a,或者只打armeabi-v8a一个文件就可以了,比如微信都只用v8a了。
android {
defaultConfig {
ndk {
abiFilters 'armeabi-v8a'
}
}
}
-
使用体积更小图片——使用wepb、SVG、iconfont图片
使用Webp来代替JPG和PNG图片,它保留了JPG和PNG优点的同时,能提供更好的压缩,达到更小的体积。
WebP的优势在于它具有更优的图像数据压缩算法,在拥有肉眼无法识别差异的图像质量前提下,带来更小的图片体积,同时具备了无损和有损的压缩模式、Alpha 透明以及动画的特性,在 JPEG 和 PNG 上的转化效果都非常优秀、稳定和统一。会比转为png和jpg的图片小25%-35%。
你可以使用矢量图形来绘制分辨率无关图标及其他可伸缩媒体文件。整个屏幕那么大的清晰图片,如果使用矢量图可能只需要100-byte大小。
-
webp和png的区别
PNG 转 WebP 的压缩率要高于 PNG 原图压缩率,同样支持有损与无损压缩
转换后的 WebP 体积大幅减少,无损压缩后的 WebP 比 PNG文件少了 45% 的文件大小,图片质量也得到保障(同时肉眼几乎无法看出差异),
转换后的 WebP 支持 Alpha 透明和 24-bit 颜色数。
可见除了 WebP 在解码时间与 PNG 有较明显差异(毫秒级别)之外,总体使用体验和 PNG 基本无差异。
解码耗时:WebP 的解码时间是 PNG 格式的 4-5 倍(24.8ms)
流畅程度:两种格式下,AIO 滑动流畅度无明显差异
CPU使用:两种格式下,连续发送 15 个表情,CPU 使用均在 10%—26% 之间波动,两者无明显差异
内存占用:两者格式下,连续发送 15 个表情,PSS 内存占用跨度均为 11M,无明显差异
使用矢量图
最佳方式,是使用矢量图。只需要一套图片,就能在不失真的方式前提下,将图片资源做到最小。从UI设计图上下载SVG格式图片资源,然后在AS中,将SVG转成Vector矢量图来使用。
-
减小classes.dex包大小
减少代码量,这个就需要看自己团队的实力了,搭建复用性更高的框架,选择更合理的开发模式来减少代码量,能不必要引入的库可以团队完成。
-
缩减资源——shrinkResources true
假如有一些资源文件不确定还用不用,也不敢删,或者不确定需求是否会变更,所以先留着,那这种情况怎么办呢? 可以使用shrinkResources来缩减资源。
buildTypes {
debug {
minifyEnabled false
}
release {
shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
要配合混淆minifyEnabled一起使用才行,原理也很简单,代码移除之后,引用的资源也就变成无用资源了,才可以进一步缩减。
-
功能重复的三方库整合
比如glide和picasso,都是图片库,保留其一即可。
-
原生改用H5或小程序等方案
有些功能可能原生做就显得太重,比如各种促销活动,需要加载各种大图,原生既重又不够动态化,这个时候H5是一种很好的替代方案。
-
资源混淆——AndResGuard
微信混淆方案(AndResGuard)是通过修改aapt在处理资源文件相关的源码达到资源文件的替换。它会将原本冗长的资源路径变短,例如将res/drawable/wechat变为r/d/a。
混淆后的资源文件夹:
1.在项目根目录的gradle文件下加入资源混淆插件:
dependencies {
classpath 'com.tencent.mm:AndResGuard-gradle-plugin:1.2.10'
}
2.在app的gradle下加入配置:
plugins {
id 'AndResGuard'
}
andResGuard {
// mappingFile = file("./resource_mapping.txt")
mappingFile = null
use7zip = false
useSign = true
// It will keep the origin path of your resources when it's true
keepRoot = false
// If set, name column in arsc those need to proguard will be kept to this value
fixedResName = "arg"
// It will merge the duplicated resources, but don't rely on this feature too much.
// it's always better to remove duplicated resource from repo
mergeDuplicatedRes = true
whiteList = [
// your icon
"R.drawable.ic_launcher*",
"R.anim.umeng*",
"R.string.umeng*",
]
compressFilePattern = [
"*.png",
"*.jpg",
"*.jpeg",
"*.gif",
"*.webp",
]
sevenzip {
artifact = 'com.tencent.mm:SevenZip:1.2.20'
//path = "/usr/local/bin/7za"
}
}
whiteList(白名单)中指定不需要进行混淆的资源路径规则,主要是针对第三方SDK,因为有些SDK的代码中通过getIdentifier()的方式引用到对应的资源文件,如果对其进行混淆,会导致找不到对应资源文件,出现crash。
使用转成aab格式的包
Google Play就是基于对aab文件处理,将App Bundle在多个维度进行拆分,在资源维度,ABI维度和Language维度进行了拆分,你只要按需组装你的Apk然后安装即可。如果你的手机是一个x86,xhdpi的手机,你在google play应用市场下载apk时,gogle play会获取手机的信息,然后根据App Bundle会帮你拼装好一个apk,这个apk的资源只有xhdpi的,而且so库只有x86,其他无关的都会剔除。从而减少了apk的大小。
避免依赖重复库
有的库依赖里面的功能看起来是重复的,那就要考虑将重复、覆盖度高的库进行选择性删除,一种功能用一个库。比如数据库操作,图片加载的,可能有些库隐藏得较深,隐藏在一些库里面,可以gradle命令 ./gradlew dependencies 打印依赖树查看有没有重复依赖库的问题。
找到之后直接移除,或者exclude移除。
本地图片转网图
我们可以手动把本地图片上传到oss-browser[17]进行预加载,然后删除本地图片,修改代码加载网络图片。
插件化技术
插件化,商业收益非常明显,基本上各个大厂都有做插件化,方便生成轻量级 Android 应用,通过插件化去加载非核心模块,大家可以看一下市面上常见的八种插件化工具对比图,再选择更适合自己企业的插件化工具。
SO动态加载
动态加载 So 库其实是一些边缘功能的 So 库或者使用时机比较晚的 So 库可以考虑动态加载;不使用时so库不再jniLibs目录下,不打进apk中。需要使用时,去网络地址下载So库,然后再loadLibrary进行加载使用。
步骤一: 下载so
步骤二:拷贝so至私有data目录
步骤三:通过绝对路径加载so
R8优化
Android构建中,在AGP3.4.0之前也是使用的ProGuard 进行代码优化混淆,但是在3.4.0之后,谷歌将这一工作赋予给了性能更佳的R8编译器。
虽然摒弃了ProGuard,但是R8编译器还是兼容ProGuard的配置规则。
使用R8编译器可以做以下优化:
1.代码缩减:
代码缩减指的是:R8编译期智能检测代码中未使用到的类、字段、方法和属性等,并移除。
2.资源缩减
资源缩减是在代码缩减之后进行的,只有去除了不需要的代码后, 才可以知道哪些代码里面的资源也是不被引入,可以移除的。
资源缩减只要在模块gradle下面添加shrinkResources属性即可。
3.代码混淆
混淆指的是将类名,方法名,属性名使用无意义的字符来表示
4.代码优化
为了进一步缩减应用,R8 会在更深的层次上检查代码,以移除更多不使用的代码,或者在可能的情况下重写代码,以使其更简洁。
R8参考:https://juejin.cn/post/7225511164120891453
实战压缩apk
当前这个demo apk压缩之前大小是25.6M,然后接下来进行瘦身。
可以看到,这个apk包体积占用大户就是res资源文件,第二大户就是代码文件,如果有so文件,会将so文件作为第三大户进行瘦身。
第一步:
开启混淆压缩代码资源:
buildTypes {
debug {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
打出新包,包体积缩小到21M,效果比较明显:
第二步:
通过unused resource删除无用资源:
并且开启shrinkResources:
debug {
minifyEnabled true
shrinkResources true //强力删除无用资源,不打包进apk,需配合minifyEnabled一起使用
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
做完压缩到20.8M,效果不明显
第三步
将apk中占用体积大比重的图片资源删除,或者用webp、矢量图来替换。
修改之前各个大图片,从几百k到1M多不等:
删除和修改为webp之后的:
做完压缩成了4.9M,压缩效果最明显:
参考:
https://mp.weixin.qq.com/s/g2j-V4Rqn4Zrb1x1Ilev2A
https://mp.weixin.qq.com/s/NiV51jOeCnTRgo-TLFsw7g
https://blog.csdn.net/Android_machong/article/details/53258924