「玲珑宝塔」优化 Apk 包大小

絮絮叨

工作不长不短,之前未曾考虑过深处,只是停留写出来了,便是完美。

而今的处境,不尴不尬,岁月刚好,背起行囊,继续前行。

如今的 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 编译器进行压缩、混淆以及优化,主要项以及作用如下:

  • 代码优化:通过检测并安全移除未使用的类、字段、方法和属性;
  • 资源压缩:从应用中移除未使用的资源,此过程包含移除库依赖项中未使用的资源文件。此项常常和代码压缩配合使用;
  • 混淆:缩短类和成员的名称,从而减小 Dex 文件大小;
  • 优化:检查并重写代码,进一步减小 Dex 文件大小。例如,如果 R8 检测到从未采用过给定 if/else 语句的 else {} 分支,R8 便会移除 else {} 分支的代码。

这里需要注意一下:

默认情况下并不启用压缩、混淆和代码优化功能。因为开启后会造成 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

混淆需注意:

  • Android 四大组件不能混淆;
  • 反射、注解、枚举不能混淆;
  • JS、Native 调用的方法不能混淆;
  • 基础 Bean 类以及序列化实体类不能混淆;
  • 自定义控件不能混淆;
  • 资源文件不能混淆(当然也有骚操作);

随后列举常用混淆规则(语法):

  • 保留某个类

-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:

这块步骤如下:

  • 导入 Mapping 文件
  • 将混淆后错误日志拷贝黏贴到 Obfuscated stack trace 中
  • 点击右下角的 ReTrace!

1.4 开启 Zipalign 优化

这块我看的很湿懵逼,估计唯有鸡大行云流水了。简单摘自官方解释:

zipalign 是一种归档对齐工具,可对 Android 应用文件进行重要的优化。其目的是要确保所有未压缩数据的开头均相对于文件开头部分执行特定的对齐。具体来说,它会使 APK 中的所有未压缩数据(例如图片或原始文件)在 4 字节边界上对齐。这样一来,即可使用 mmap() 直接访问所有部分,即使其中包含具有对齐限制的二进制数据也没关系。这样做的好处是可以减少运行应用时消耗的 RAM 容量。

如何使用?很是 easy~

buildTypes {    release {        // 开启Zipalign 优化        zipAlignEnabled true    }    debug {        zipAlignEnabled false    }}

本文分享自微信公众号 - 贺利权(hlq_struggle)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-11-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Flutter笔记

Flutter实战 | 从 0 搭建「网易云音乐」APP(六、歌词(一))

本系列可能会伴随大家很长时间,这里我会从0开始搭建一个「网易云音乐」的APP出来。

14610
来自专栏Python绿色通道

薅羊毛 | Python 自动化带你轻松赚钱(完结版)

最近,有一个朋友告诉我,她在某平台上购买了一部手机,收到货之后发现商品质量挺好的,价格也不贵。

19930
来自专栏sringboot

Spring MVC组件

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

5840
来自专栏FreeBuf

由恶意GIF文件引发的RCE漏洞,超过40000个应用受影响

本月初,新加坡安全研究员@Awakened披露了关于WhatsApp(2.19.244之前版本)存在的RCE漏洞(CVE-2019-11932)利用的文章,该漏...

9820
来自专栏程序亦非猿

Flutter 中文文档:简单的应用状态管理

现在大家已经了解了 状态管理中的声明式编程思维 和 短时 (ephemeral) 和应用 (app) 状态的区别 之间的区别,现在可以学习如何管理简单的全局应用...

13910
来自专栏Android 开发者

使用 Kotlin 构建 Android 应用 | Kotlin 迁移指南 (上篇)

今年五月份的 Google I/O 上,我们正式向全球宣布 Kotlin-first 的这一重要理念,Kotlin 将成为 Android 开发者的首选语言。接...

9120
来自专栏EAWorld

浅析RunLoop原理及其应用

一个APP的启动与结束都是伴随着RunLoop循环往复的,不断的循环、不断的往复。当线程被杀掉、APP退出后被系统以占用内存为由杀掉,RunLoop就消失了。但...

8720
来自专栏AI科技评论

干货 | TVM:Deep Learning模型的优化编译器(强烈推荐, 附踩坑记录)

作者知乎网址:https://www.zhihu.com/people/ming-zi-zong-shi-hen-nan-qi/activities

12220
来自专栏Android 技术栈

gradle 从3.0.1升级到 3.4.0 所解决的各种问题

升级到3.4.0后如果里面有android.enableAapt2=false会报错,去掉即可

14430
来自专栏测试开发社区

聊聊 Airtest 自动化工具

很多读者看过之前的文章,发现我使用最多的是一款 Airtest 的自动化测试框架。

15330

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励