APK的瘦身设计方案

APK的瘦身设计方案

1 APK瘦身前言

在开发过程中;由于业务的扩展;版本的迭代;第三方的集成等开发工作,我们安装包越越来越大;导致下载安装的过程中越来越慢.影响到用户的体验,瘦身的目的最明显的一个就是:提高下载转化率。怎么理解呢?举个例子来说,假如我们的盛钱包成长版应用包20MB+,100个潜在用户想要去下载尝试使用你的应用,在移动网络的情况下,结果有20个用户嫌弃安装包太大而直接放弃,有30个用户在等待下载的过程中取消下载,wifi情况最终只有50个用户下载安装了应用。这时你的应用的实际下载转化率其实是50/100 =50%。

另外一个;apk的瘦身;可以为用户节省不少的流量;对我手机流量不多的人;是一个福音啊.... 
简单的总结:安装包越小,用户下载等待的时间越短,对手机配置要求的也越小,设备的体验愈佳,应用的下载转化率也就越高。

2 APK安装包的组成结构分析

开始瘦身前,需要先了解一下APK都主要由哪些成分组成.我以盛代宝目前安装包的分析结果图如下:

APK的瘦身设计方案_第1张图片

 TIP:比例分析构成图(比例会自动按从大到小排好序呈现 

APK的瘦身设计方案_第2张图片

 

(TIP :目前盛代宝经过优化打出的包的大小是6.33M)

1 classes.dex 编写的所有的Java代码(包括各种引入的sdk代码)最终转化成在Android虚拟机上运行需要的字节码

2 res文件夹存放所有资源文件夹(除了里面raw文件夹的文件不会被编译,其他都会被编译)

3 resources.arsc 编译后的二进制资源文件

4 assets文件夹 用于保存需要保持原始文件的资源文件(这部分资源不会被编译)

5 lib 存放一些不同cpu 架构的so文件

6 AndroidManifest.xml 程序全局配置文件

7 META-INF文件夹 存放几个签名校验相关的文件,用于保证APK的完整性和安全性

8其他 一些配置生成的文件

APK瘦身精简内容概要

APK 的瘦身 主要针对assets、classes.dex、lib、res内容进行精简.

1 classes.dex文件——混淆压缩代码

第一,现在写的app 基本都是经过混淆了的,如果不混淆, 发布出去,别人一反编译 就可以直接看你的源码了,一般为了提高安全性会选择混淆;加大了反编译后阅读理解的难度.
第二;代码通过混淆之后在一定的程度上减小应用体积.
混淆不仅能将代码中的类名、字段、方法名变为无意义的名称,保护代码,也由于移除无用的类、方法,并使用简短名称对类、字段、方法进行重命名缩小了程序的大小。
第三 开启混淆的步骤:
A要通过Proguard启动代码压缩,在build.gradle文件内相应的构建类型中添加minifyEnabled true。

 APK的瘦身设计方案_第3张图片

B proguardFiles getDefaultProguardFile 就是制定 混淆规则的文件, AndroidStudio默认生成了proguard-rules.pro 文件

 APK的瘦身设计方案_第4张图片

C 混淆规则定义

目前网络上现在大部分都有混淆模板,以及在GitHub 上也有混淆的插件可以集成 AndroidProGuard 插件;一般都是基于混淆模板上去添加自己想要的混淆规则,一般遵循以下混淆规则

###-----------基本配置-不能被混淆的------------###-

-keep public class * extends android.app.Activity

-keep public class * extends android.app.Fragment

-keep public class * extends android.app.Application

-keep public class * extends android.app.Service

-keep public class * extends android.content.BroadcastReceiver

-keep public class * extends android.content.ContentProvider

-keep public class * extends android.app.backup.BackupAgentHelper

-keep public class * extends android.preference.Preference

###-----------support.v4/v7包不混淆------------###-

 

###-----------保持Serializable不混淆------------###-

 

###-----------保持 Parcelable 不混淆------------###-

 

###-----------不混淆资源类------------###-

 

###-----------保持 native 方法不被混淆------------###-

 

###-----------保持自定义控件类不被混淆------------###-

 

###-----------保持枚举 enum 类不被混淆------------###-

 

###-----------保持自定义控件类不被混淆------------###-

 

###-----------保持实体类不被混淆------------###-

 

###-----------保持jar包不被混淆------------###-

 

###-----------保持反射相关的类和方法不被混淆------------###-

 

###-----------保持webview 与js互相调用的类 不被混淆------------###-

 

###-----------保持注解继承类不混淆------------###-


Tip:另外如果我们项目应用到第三方sdk 的混淆;如百度,友盟,极光等一般都是从官网上提供的混淆规则里复制;避免出现意外的错误

第四 移除废弃功能的代码

不要只是注释,担心可能以后会用到。因为一般的开发都会使用版本控制工具git svn等,所以这种担心是多余的。

第五 定期 检验 项目代码的习惯

发现有重复功能实现的代码或者框架要及时重构,删除重复部分的代码和框架。出现重复功能代码的情景大多如下:已经有了的功能代码或框架,团队成员不知道自己又写了一套或者引入另外的相同功能的框架。这种情况的发生也反映出你们团队之间的沟通存在一定的问题。有可能是个人经验问题,也有可能是整个团队的规范,共识问题,导致大家都不重视。

第六 业务模块采用插件化框架

插件化,一种懒加载思想的体现,先让用户能够安装宿主包,对于一些功能模块做插件化,在特定的时机再下载安装。

(Tip 比如现在github比较火的Small ,滴滴插件;还有360插件化,有空可以研究研究以下;绝对有好处)

2 assets精简

放在assets下的文件不会生成ID,存放的文件形式可以是多样的比如音频、图片、html,配置信息相关的等等,精简体积也就是精简这些内容。

(1)音频:主要用在铃声和通知方面,体积不要太大,使用压缩格式的音频
(2)图片:在不降低图片效果、保证APK显示效果的前提下缩小图片文件大小,可以使用tinypng进行图片压缩
(3)WEB页面:可以考虑使用7zip压缩工具对该文件进行压缩,在正式使用的时候解压

3 resources.arsc文件

简单介绍下resources.arsc文件来源与作用:除了assets和res/raw资源被原装不动地打包进APK之外,其它的资源都会被编译或者处理。除了assets资源之外,其它的资源都会被赋予一个资源ID。打包工具负责编译和打包资源,编译完成之后,会生成一个resources.arsc文件和一个R.java,前者保存的是一个资源索引表,后者定义了各个资源ID常量,供在代码中索引资源。所有的png文件是以STORE的方式存储到apk里的,通俗的说,当文件是STORED的方式存储到zip,表示这个文件并没有经过压缩,现在业内有一个开源的插件针对以上原理进行了一定的压缩;它就是如下压缩插件

微信资源压缩插件:AndResGuard 其原理就是:(可以研究一下;或许有意外的收获)
(1)对资源(png, xml, jpg等)名称混淆,资源路径名称混淆以及名称长度压缩
(2)将原来以STORED形式存储到zip中的png文件改成DEFLATED(普通压缩存储)方式。

4lib文件夹

lib目录用于存放通过C或C++编写编译生成的so文件(native库/JNI开发)

APK的瘦身设计方案_第5张图片

目前市场上主流的架构还主要是arm架构,所以如果不是必要的话,可以考虑不支持x86和mips架构,但这并不意味着CPU是x86或mips架构的手机就不能正常安装使用APK了,因为放在arm目录下的so库是可以兼容到其他架构的; 

另外arm架构中的eabi-v7a相比于eabi只是在图形渲染方面有了很大的改进,所以如果so库对图形渲染没有很高的要求的话,完全可以把so库只存放在arm eabi目录中,这样可以大大减小APK的体积。 

lib瘦身主要是减小对 CPU 架构的支持,配置起来很简单,在 build.gradle 使用 abiFilters 配置需要用到的 CPU 架构,并将不需要兼容的 so 文件从项目中移除即可。 一般只要支持armabi和x86就够了 示例代码块如下:

 APK的瘦身设计方案_第6张图片

5减res文件夹

res文件夹里面主要就是包括各种布局文件,value文件,图片文件,原生文件。这一块的处理方案主要采用2种方式,一是压缩资源,二是删除未使用的资源。

(1)压缩图片,一般而言图片压缩对减小Apk大小所产生的效果占到你所有减小Apk努力的效果50%以上,推荐一款目前所知图片压缩效果最好的网站TinyPing, 我举个例子;你能看得出下面压缩之后的差别吗?

 APK的瘦身设计方案_第7张图片

(2)移除无用的资源  这里的移除无用的资源,主要是指2个方面,一是在工程里面直接删除没有使用的资源,二是不打包没有使用的资源。

A) 在工程里面直接删除没有使用的资源 Android Studio 选中项目右键 =>Refactor =>Remove Unused Resources

 APK的瘦身设计方案_第8张图片

B)不打包不需要使用的资源 利用Android Plugin开启gradle 的Resource shrinking进行构建打包,这时候没有被使用的资源将不会打进包里

 APK的瘦身设计方案_第9张图片

(3)尽量只保存一份图片资源

开发目录下会有个drawable或者mipmap目录用于适配不同dpi的屏幕,Android界面尺寸:480*800、720*1280、1080*1920 (美工在切图是基于一套分辨率进行切图) 目前市面上绝大部分机型都处于xxhdpi的适配范围,所以可以考虑只保留xxhdpi目录下一份图片资源即可;目前公司基于720 来切图就可以了;

(4)尽量使用 Drawable XML、Color代替PNG图片

一些情况下,我们可以考虑使用 Drawable XML 来代替 PNG,如:渐变的背景图,用几行 XML 就可以描绘出来,何必使用几十到上百K的 PNG 文件, 如下图其实都是可以不用图片就可以实现的一些简单的功能

 APK的瘦身设计方案_第10张图片

图形显示;比如圆角的按钮,圆形的UI 我们自己绘制,可以减少图片的导入;减少APK 的体积.

(5)不需要透明度时使用JPG代替PNG 
 当不需要透明度的图片时,可以考虑用JPG代替PNG,由于JPG没有Alpha 通道,所以文件更小
(6)考虑使用WEBP图片资源格式

WebP是谷歌研发出来的一种图片数据格式,它是一种支持有损压缩和无损压缩的图片文件格式,如果应用支持到Android 4.0+,那么我们可以使用WebP格式代替PNG,我们的资源大小能降低50%多。 
不过就目前来说,对于4.0+ 到 4.2.1 ,原生只支持完全不透明的webp图,4.2.1+ 对于webp的是完全支持的(包含半透明的webp图)。所以说对于4.2.2(API17)以下的版本,还是需要引入兼容库来解决。但是另外一点,引入兼容库又会导致包体变大。不过这种增量或许和把所有png图换成webp所带来的减量比较或许不值得一提,特别是图片特别多的应用,这种增量几乎可以不计。另外也要注意的是,某些国产rom会代理类Resource为自己定义的,例如小米2刷成4.xx的手机上,小米机器代理了类Resource为MIUIResource,但是这个MIUIResource未能正确识别webp资源,会导致加载资源文件失败而出现崩溃。所以应该考虑自己用户的机型分布,考虑使用WEBP图片资源格式替换png格式。

总结

APK 的瘦身好处; 就不言而喻了;或许还有其他有用的方案;这些也需要大家提出完善;可能我总结的还不是很完美;目前我是拿了盛代宝做试点;效果还是看的见; 目前经过不断的优化; 目前包的大小维持在5M+;个人觉得还有优化的空间; 如果时间充裕,这个我会持续的优化下去;项目都是在不断优化;不要怕犯错,用心去做一件事;你会收获很多,善于总结;经验是累积的 我相信你可以为了你的项目瘦身做出很大的贡献。如果有好的建议;欢迎大家都提出来;我将继续完善这个文档.


你可能感兴趣的:(android,技术博客)