絮絮叨
工作不长不短,之前未曾考虑过深处,只是停留写出来了,便是完美。
而今的处境,不尴不尬,岁月刚好,背起行囊,继续前行。
如今的 5 G 也在万众瞩目瞩目下翩翩起舞,而 Android 近些年也惹得不少争议,所谓的谣言,不过尔尔。
每个人的追求不一样,尽自己最大努力吧。
如何减少 Apk 大小,一直以来都是处于观望状态,懒得折腾,其实还是不会,Low 的一批。
Today,一起来搞一波~
欢迎各位指正~
现学现卖~
一脑图,览无余
玲珑宝塔镇万物
首先附上一张现在 Apk 大小图:
未做任何处理原包大小为 10 MB,加固之后将近 11 MB。
以此为例,一起看看经过我们玲珑宝塔升级完,最终还剩下多少精华?
一层镇妖魔(减少 4.1 MB)
来到第一层,我们先来简单分析下是什么造成 Apk 包如此“庞大”?
上图可看到 lib 下兼容了全面的 CPU 架构,试想一下,假设未来的未来多了短视频、直播、地图导航等等(不接受杠精),这块的大小会不会成倍数的增长。
上图可看到默认支持了 89 种语言类型,目前的应用暂时未国际化,这块也可直接设置兼容中文即可,原谅我这个强迫症。
占比排行榜依次为:源代码、资源文件、lib。
我们先挑个软柿子玩玩。
1.1 设置支持语言(减少 0.2 MB)
关于这块,个人觉得虽然占比较小,但是用啥玩啥,用不到的直接干掉。
在 build.gradle 中设置仅支持中文:
defaultConfig { ... // 仅支持 中文 resConfigs "zh"}
这块主要是根据现有项目需求来定,中心思想只有一个,兼容哪儿个就设置哪儿个国家语言,其他的直接忽略。
设置完之后打个包,看下有没有什么变化。
从上图中可以很清晰的看到,经过设置仅支持的国家语言后,包大小减少了 0.2 MB。随后我们看下资源映射文件中关于 string 中会有什么变化。
默认语言中设置为中文,且应用也只支持了中文,少了好多东西,爽得很~
1.2 设置支持的 CPU 架构类型(减少 1.5 MB)
话说这里的 lib 为何兼容了这么多的 CPU 架构类型???
正好走到这里,关于这块的小知识再次重温下,瞅瞅 Google 为我们提供的解释:
不同的 Android 手机使用不同的 CPU,而不同的 CPU 支持不同的指令集。CPU 与指令集的每种组合都有专属的应用二进制接口,即 ABI。ABI 可以非常精确地定义应用的机器代码在运行时如何与系统交互。您必须为应用要使用的每个 CPU 架构指定 ABI。
貌似 Google 商店现在支持对应的架构模式分发对应的 Apk 包,这点爽的每个包只需要兼容一种就好了。But,ummm。
目前而言,项目中使用到真正用到 So 库没几个,全部兼容太过于浪费,据说 arm 属于通用,那么这里同语言设置一样,仅支持 arm 即可。
defaultConfig { ... ndk { // 设置支持的SO库架构 abiFilters "armeabi" }}
打包运行后,继续查看现在包大小:
这块一直属于个心病,之前的项目光是 So 库就占了很大一部分空间,很湿蛋疼。
1.3 开启压缩、混淆(减少 2.4 MB)
根据 Google 官网解释,当我们使用 Android Gradle 3.4.0 或者更高版本时,默认会启用 R8 编译器进行压缩、混淆以及优化,主要项以及作用如下:
这里需要注意一下:
默认情况下并不启用压缩、混淆和代码优化功能。因为开启后会造成 Debug 模式下编译时间较久。
关于混淆文件,这里需要正好学习一下。
混淆的意义在于什么?(引入官方解释)
混淆处理的目的是通过缩短应用的类、方法和字段的名称来减小应用的大小
混淆效果(摘自官方):
androidx.appcompat.app.ActionBarDrawerToggle$DelegateProvider -> a.a.a.b: androidx.appcompat.app.AlertController -> androidx.appcompat.app.AlertController: android.content.Context mContext -> a int mListItemLayout -> O int mViewSpacingRight -> l android.widget.Button mButtonNeutral -> w int mMultiChoiceItemLayout -> M boolean mShowTitle -> P int mViewSpacingLeft -> j int mButtonPanelSideLayout -> K
混淆需注意:
随后列举常用混淆规则(语法):
-keep public class com.hlq.Love
-keep class com.hlq.** {*;}
dontwarn com.hlq.**
具体规则可文末查看官方手册。
接下来跟着官网一起实践一波~
buildTypes { release { // 打开资源压缩 shrinkResources true // 开启混淆操作 minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' signingConfig signingConfigs.config } debug { // 关闭资源压缩以及混淆操作 shrinkResources false minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' signingConfig signingConfigs.config }}
这里需要注意,在 Debug 模式下需要关闭资源压缩以及混淆操作,否则会增加编译时间,一般在发布正式包时打开即可。
混淆文件点击原文查看吧。
随后我们继续打包,查看混淆、资源压缩后 Apk 大小以及部分变化:
dex 从 3 个降低到 2 个。未 Keep 的文件均已混淆,而 Keep 的文件依旧傲娇挺立,如下图:
混淆操作,在一定程度增大了破解的难度。当然,也没有绝对的安全。
R8 每次运行时都会创建一个 mapping.txt 文件,其中列出了混淆过的类、方法和字段名称与原始名称的映射关系。此映射文件还包含用于将行号映射回原始源文件行号的信息。R8 将此文件保存在 /build/outputs/mapping// 目录中。
线上版本肯定要进行混淆,那么针对线上版本报出的异常,我们又该如何处理呢?毕竟关键内容都变成无意义字符,鉴名其意不存在了。
iTerm 2 打开:
点击 ReTrace:
这块步骤如下:
1.4 开启 Zipalign 优化
这块我看的很湿懵逼,估计唯有鸡大行云流水了。简单摘自官方解释:
zipalign 是一种归档对齐工具,可对 Android 应用文件进行重要的优化。其目的是要确保所有未压缩数据的开头均相对于文件开头部分执行特定的对齐。具体来说,它会使 APK 中的所有未压缩数据(例如图片或原始文件)在 4 字节边界上对齐。这样一来,即可使用 mmap() 直接访问所有部分,即使其中包含具有对齐限制的二进制数据也没关系。这样做的好处是可以减少运行应用时消耗的 RAM 容量。
如何使用?很是 easy~
buildTypes { release { // 开启Zipalign 优化 zipAlignEnabled true } debug { zipAlignEnabled false }}