Apk使用与修改Android开发Android知识

「Android」 APK瘦身探索

2017-04-06  本文已影响500人  尚妆产品技术刊读

本文来自尚妆Android团队青峰
发表于尚妆博客

APK瘦身探索

最近几周一直在研究如何为APK瘦身,折腾了很久,是时候写篇博客总结一下了,虽然已经准备了下周一要在客户端周会分享用的PPT:APK瘦身探索

价值

虽然说APK瘦身对于Android对应用可分配内存的限制影响不大,但是还是有一些影响的,就以图片为例,将一些小图标替换为iconfont能有效减小内存的分配,防止OOM的出现。

另外,无论是iOS开发者还是Android开发者都应该尝试最好学会如何为IPA或APK瘦身,不仅仅是为了帮助用户省流量、减少下载时间、减少占用的存储空间等等,更重要的是为了<font color='#ee6252'>提高转化率(注意:本文的转化率均指下载转化率)</font>。

那转化率是什么呢?

举个栗子:你的应用大小是 18MB ,有100个潜在用户想要去下载尝试使用,结果有20个用户嫌弃安装包太大直接扬长而去,有20个用户在等待下载的过程中取消下载,最终只有60个用户真正下载安装,那么应用的转化率就是 60/100 = 60% 。

那为什么要提高转化率呢?

因为用户在纠结下载你的产品还是你的竞品的时候,往往会选择那个体验最好、功能最多、性能最好、包最小的。

工具

如何有条理的为APK瘦身,必须知道APK的目录结构,不过在讲述这个之前,我这里先介绍几个工具,在后文会用到。

AndroidStudio2.2.3

AndroidStudio升级到版本2.2.3之后提供了Analyze APK的功能(不过作为AS粉想必已经升到AS2.3了吧,哈哈),我们可以借助该工具清楚的了解APK的下载大小、解压之后的大小、内部各个文件夹或文件占用的大小等信息,进而得知那些地方可以优化。下图为目前达人店APK的内部信息:

APK Info

另外使用该工具还可以反编译资源文件、还原layout中的资源id,分析DEX、显示每一个文件夹或文件的方法数,分析哪些第三方库方法数很多但实际只用到了一部分等其他功能。

最后如何使用该工具?有以下两种方式:

  1. 直接将APK拖拽进入AndroidStudio即可
  2. 点击菜单栏Build-Analyze APK...选项,再选择需要分析的APK即可

NimbleDroid

NimbleDroid 是美国哥伦比亚大学的博士创业团队研发出来的自动化分析Android app性能指标的系统,分析的方式有静态和动态两种方式:

其中静态分析可以分析出APK安装包中大文件排行榜,各种知名SDK的大小以及占代码整体的比例,各种类型文件的大小以及占排行,各种知名SDK的方法数以及占所有dex中方法数的比例,针对缓慢的方法,缓慢的第三方SDK和内存泄漏。

其中动态分析可以测量生成的速度、网络、内存和磁盘使用率。

我用了一下上面这个工具,感觉还是不错的,下面我们来看几张有逼格的图(图中数据来自于达人店APK):

APK内部各类型对应文件占用的大小

Size by Type

APK内部各个类库的方法数

Method Count

APK启动过程中各个方法的执行时间

Hung CPU Methods

ClassShark

ClassShark 是一款查看Android执行文件(apk)的浏览工具,目前有两个android App(Apk)和桌面(jar)的版本。

使用这款工具,可以很方便的打开APK、Class、Jar、res等文件和分析里面的内容。

ClassShark

不过目前这个工具并不需要我们单独使用,因为AS内部的分析工具就是用的这个。

通过以上工具,我们可以方便快速的分析APK,找出那些可以优化的部分,为了更加有条理的进行讲解,下面我会按照APK的目录结构来逐条阐述。

APK目录结构

APK_taobao APK_weixin

可以看出淘宝和微信也是这样处理,所以我们其实也可以这样操作。

res目录

res目录用于存放应用程序的资源文件,主要包括布局文件、图片、XML配置文件等,它包含以下几个特性:

  1. 使用Resources类管理资源
  2. res目录内部文件会被系统编译
  3. res目录不支持任意深度的子目录
  4. 获取资源不需要通过相对路径找寻,因为文件会被系统编译,所以需要通过资源ID(注:资源ID被存放在resources.arsc文件中)查找

其基本目录结构如下图所示:

res目录结构

上图比较全面的列举了res目录下经常包含的子目录和文件,并解释了各个子目录或文件的含义。

根据上图我们显然可以发现,res目录就是我们APK瘦身里面的一大重要部分了,由于其包含的知识很大,下面我会分章节进行阐述,尽量一一阐述清楚。

只用一套图

首先我给出这么一个结论:一个APK尽量只用一套图片,从内存占用和适配的角度考虑,建议放在xhdpi文件夹下。

那么为什么要把图片放在xhdpi文件夹下面呢?

由于此处知识涉及到Android屏幕适配方面的知识,比较复杂。本文是关于APK瘦身的,所以就不详细讲解了。下面进行必要的阐述,首先让我们来看两张图:

Remove Unused Resources

然后根据查找到结果,逐条双击打开文件,按快捷键fn+option+F7进行查找,然后在分析是否应该删除,<font color='#ee6252'>注意:此处定要慎重,务必自测!!!</font>。

另外,我们还可以通过将某些图片转换网络图片的方式解决,但是这个操作也是需要<font color='#ee6252'>慎重</font>的,最重要的一点是<font color='#ee6252'>不能影响用户的体验</font>。这边路飞同学制作了一个Chrome插件来帮助我们快速上传图片到cdn中,可以通过此处下载:joyuploader

最后,还有一种办法:使用AndroidStudio提供的Lint工具对工程做静态代码检查,它不仅可以找出我们在代码编写上面的失误,还能够列出那些未被使用的资源,甚至还可以指出哪些地方可能存在内存泄漏等等,功能非常庞大,所以如果工程较大的话,还是比较耗时的,当然这并不是问题,因为我们可以针对某个模块执行静态代码检查。我们可以通过<font color='#ee6252'>选中菜单栏Analyze-Inspect Code...选项</font>执行静态代码检查,执行完成的效果图如下所示:

Lint

资源混淆

目前我们不仅在资源(特指图片)质量方面做到了极致,在资源数量方面也做到了极致,看起来真的到极致了。其实不然,我们还可以使用资源混淆的方式为APK瘦身,通过压缩文件内容,减少文件名长度的方式实现。

目前比较出名的资源混淆方式是微信的AndResGuard美团的修改AAPT,不过由于美团的资源混淆方法非常麻烦,还有如果需要通过getIdentifier的方式获取资源时需要保证这些资源的名字不被混淆,美团很难实现,所以目前大家都在用微信的资源混淆方式,因为微信使用方便,而且提供了白名单。

下面是达人店APK未使用微信资源混淆和使用了微信资源混淆的差异:

shopandroid-debug.apk shopandroid-debug_signed_7zip_aligned.apk

可以清楚的看到,在使用了微信资源混淆之后,APK减少了0.7MB左右,效果还是十分明显的。

那么为什么使用了微信资源混淆之后可以实现APK瘦身呢?下面这两张图清楚的展示了瘦身的原因(摘自微信资源混淆官方文档):

总结,安装包大小减少的原因以下四个:

jar2dex

既然dx工具已经办帮我们压缩了那么多,那我们还有什么好压缩的呢?

当然有,因为dx工具并没有压缩class的内容,所以我们的源代码并没有得到压缩,下面我先介绍两种常见的办法来解决这个问题:

  1. 和之前最简单的资源压缩方式一样,我们也可以在主模块的gradle文件中配置minifyEnabled实现代码混淆,从而减小java文件的大小。因为混淆后的代码将较长的文件名、实例、变量、方法名等等做了简化,从而实现字节长度上的优化。

  2. 我们也可以使用之前所说的AndroidStudio提供的Lint工具执行静态代码检查,进而删除无用的类、方法、变量等。

上面的两种方式虽然能够帮助我们减少APK的大小,但是实际上我们还可以做的更多。因为上面两种方式是自动化的,所以必然不像人那么智能。

有时候我们可能遇到这样的情况:我们引用了一个第三方类库,但是只用到了其中的几个功能,其他的大部分功能一直不用,这不是白白的浪费了用户的流量,降低了APK的下载转化率么?为了解决这样的问题,我们必须借助一些工具去找到这样的类库,比如在文章开头介绍过的工具:NimbleDroid,下面是达人店APK目前存在的某个这样的第三方类库:

Method Count Of ZXing

该类库在达人店APK中只用到了扫一扫和生成二维码这两个功能,然而这个类库定义的方法数竟然有1428,显然不合理,完全可以抽离其内部的扫一扫和生成二维码代码,单独实现。

ReDex

最后介绍一下Facebook开源的一个减少APK大小以提高性能的工具 -- ReDex,它通过内嵌以及清除僵尸代码这样的优化方式来减少字节码,其主要是对DEX做了优化,能够让APK运行更快,不过需要多测试是否会崩溃。

下面分别是ReDex的教程地址和GitHub地址:

Open-sourcing ReDex: Making Android apps smaller and faster | Engineering Blog | Facebook Code | Facebook

facebook/redex: A bytecode optimizer for Android apps

我个人由于时间问题,目前还未接入该工具,下面就展示一下网友u012124438的测试数据好了:

ReDex

后来我在使用 Redex 压缩和优化 Android APK一文的帮助下,成功的安装并使用了ReDex,但是发现了以下两个问题:

  1. 用ReDex处理过的APK,其内部的META-INF目录会被删除,虽然可以将ReDex处理过的APK用AndResGuard处理一下,会重新出现该目录。
  2. 用ReDex处理过的APK,安装好之后会出现Crash的问题,目前达人店APK要Crash三次之后才能正常使用,而且它对于达人店APK的贡献只有20~25K,所以并未打算接入。

resources.arsc

最后就是对于resources.arsc文件的压缩处理了,其实这里我们也不需要做什么,首先因为该文件记录的是资源文件和资源ID的映射关系,并没有什么值得压缩的地方;另外如果真的有值得压缩的地方,也只有资源文件的名字了,不过这个早就在之前因为我们使用了微信资源混淆解决了,所以此处就不再多讲了。

至此,针对于APK目录结构,逐条分析如何为APK瘦身已经讲完了,接下来介绍一下其他的压缩方式。

其他方式

使用APK Splits构建APK

虽然我们上面很好的使用了resource shrinker可以回收一些未使用的资源(v7、v4、google Service 等Libarry资源),但有些资源仍然未被清除。

例如:那些未使用的多套替代资源,或者是library内部隐患着引用着的资源而我们却没有使用到。或者是我们要根据用户的手机去提供不同版本的APK,如分辨率(xxhdpi,mhdpi等),so库等。那么我们可以使用APK Splits大大的减少一些无用的资源,这里我们主要参考了http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits文档。

使用多版本的APK

Multiple APK Support是一个在Google Play,可以发布不同的应用程序,分别针对不同的设备配置特征。每个APK是一个完整的、独立的应用程序版本,但他们分享在Google Play相同的应用程序清单,必须共享相同的包名和与签名。Google Play 会自动给你匹配相应的APK,这样我们的APK 就可以是分不同版本构建需要资源文件,从而减小APK的大小。

资源动态加载

我们可以在项目中使用资源动态加载形式,例如:表情,语言,离线库等资源动态加载,减小APK的大小。

支持插件化

未来对于一些独立业务模块,可以做成插件化动态加载,用户需要使用时,只需下载少部分插件。

使用shape背景

特别是在扁平化盛行的当下,很多纯色的渐变的圆角的图片都可以用shape实现,代码灵活可控,省去了大量的背景图片。

使用着色方案

相信你的工程里也有很多selector文件,也有很多相似的图片只是颜色不同,通过着色方案我们能大大减轻这样的工作量,减少这样的文件。

借助于android support库可实现一个全版本兼容的着色方案,参考代码:DrawableLess.java

其他方式...

总结

如果你不是一个Android开发人员,对于之前的阐述可能非常模糊,并不能明显的表现出APK瘦身这件事情的意义,下面我就来总结一下:

首先,针对于达人店APK做了哪些应用?

  1. 字体文件使用Glyphs进行压缩,图片使用tinypng进行压缩

  2. 只是用一套so文件

  3. 只使用一套图

  4. 使用WebP图片或SVG图片替换某些PNG或JPG图片

  5. 使用Google提供的Gradle插件实现代码混淆和资源混淆

  6. 借助NimbleDroid、AS Anylze/Lint工具分析查找删除不需要的代码或资源

  7. 使用微信提供的资源混淆工具(处于稳定性测试阶段)

  8. 使用Facebook提供的ReDex工具(处于调研阶段)

其次,APK瘦身的效果如何?

这里我们就直接看图好了:

APK瘦身效果APK瘦身效果

可以明显的发现,达人店APK越来越小了,所以说,这个工作是很有意义的。

最后,做一下竞品分析?

竞品分析竞品分析

根据上面图表,可以发现我们的APK的大小是十分有优势的,能够很好的提高下载转化率。而iOS那边显然就比较大了,虽然两者之间不能比较,但是还是可以进行一系列优化的。

忠告

最后的最后,我想对大家说:在APK瘦身的道路上,一定要掌握好,安排好事情的优先级,如果目前要做的事情、要优化的方面比较复杂,不仅需要花费很长的时间,而且最终效果也不明显,可以考虑之后再做,甚至不做。

参考链接

  1. 【Android技术专题】APK瘦身看这一篇文章就够了
  2. 那些你不知道的 APK 瘦身,让你的 APK 更小
  3. Android 性能优化系列 之 apk 瘦身
  4. APK文件结构和安装过程
  5. Android开发之资源目录assets与res/raw的区别分析
  6. Android开发之assets目录下资源使用总结
  7. Android开发:最全面、最易懂的Android屏幕适配解决方案
  8. 是时候使用 webp 给 apk 瘦身了!
  9. Dex文件格式详解
上一篇 下一篇

猜你喜欢

热点阅读