0
点赞
收藏
分享

微信扫一扫

Android 应用瘦身

瘦身目的

开发过程中,随着功能不断的迭代,包体积也会逐渐变大,如果此时将包投入市场,将会引来客户的投诉和抱怨。体积大一方面是浪费用户数据流量,另一方面是增加了安装的等待时间,用户可能因为嫌弃安装包太大扬长而去,对企业利润有着直接的冲击,所以应用瘦身环节尤为重要。下面以企业项目做实例分享一下瘦身经验。

基本思路

其实很简单,主要分两大步骤:了解安装包的组成部分,对安装包的资源目录瘦身

在代码结构双击打包好的apk会出现以下信息,可以直观的看到安装包结构:
在这里插入图片描述
通过上图,我们可以知道哪些模块最影响包的体积,根据对体积的影响程度做好排序,优化方向需围绕以下几个目录。

  1. assets
  2. lib
  3. res
  4. .dex
  5. .arsc
  1. assets。该目录下存放资源文件,例如音频文件、json、web等。但下图可以看到该目录下存放的全是字体
    在这里插入图片描述
    针对字体,给出两种建议:

    a.先检查下所需字体Android是否提供

    b.可以通过提取所需文字的ttf文件,大幅减小ttf体积

    若需语音播报,我们会将音频文件放置assets。选用音频文件优先考虑MP3、AAC等有损格式而非PCM、WAV无损格式。有损和无损在语音质量方面差别甚微、但文件大小却是天差地别

    若应用需要内嵌web,即应用在同一局域网内浏览器打开web和应用主程序实现交互场景。web端所需的某些元素可以存放在文件系统而非assets

    如非必要,考虑是否可通过网络存储、文件存储等其他方式保存资源,视具体情况而定,原则上尽量不参与打包

  2. lib。lib下存放各种架构的so文件,现在大部分机器的cpu架构是armv7,所以我们打包时只需加入以下代码过滤掉其他的abi(最终根据实际情况)。具体路径:app目录下的build.gradle
    在这里插入图片描述
    附上代码:

    ndk {
        abiFilters  "armeabi-v7a"
    }
    

    效果:优化前在这里插入图片描述
    效果:优化后
    在这里插入图片描述

  3. res。这里都是一些资源文件,包含mipmap、drawble、layout等资源文件。优化方向主要有两个:

    使用第二种方式“shrinkResources“时需关注两点:

    a.shrinkResources的使用一定要配合minifyEnabled,只有minifyEnabled为true时shrinkResources才会生效。具体原因就是我们的资源都是代码中使用的,我们需要知道哪些资源被代码使用,所以先得检测代码,即代码压缩/代码混淆

    b.shrinkResources默认发现代码中调用资源R.mipmap.a,则其他未使用资源R.mipmap.a*也会被打包进apk(*代表任意字符或字符串),所以如果您想自定义要保留的资源,则在路径res/raw/keep.xml定义规则

    <?xml version="1.0" encoding="utf-8"?>
    <resources xmlns:tools="http://schemas.android.com/tools"
        tools:discard="@color/selector_tint_color"
        tools:keep="@layout/activity_test1,@layout/activity_test2"
        tools:shrinkMode="strict"/>
        <!--discard:做严格检查-->
        <!--keep :不做严格检查-->
        <!--shrinkMode="strict" :该模式只保留在代码或者资源文件中明确引用的资源-->
        <!--shrinkMode="safe" :该模式会保留所有明确引用的资源以及可能被 Resources.getIdentifier() 动态引用的资源-->
    

    注意:当使用lint删除资源文件时,对于代码中使用了getIdentifier(String name, String defType, String defPackage)设置图片,这就需要格外小心了。我们一般的做法就是用lint检测无用资源然后删除,但getIdentifier()函数并不直接引用资源文件,而是输入资源名称,从而引起“资源文件不存在“的报错

    下表是我测试的一组对照数据,根据自己的经验总结:

    PNG2.3M(大图)124K(小图)原图
    SVG(矢量)1.44M257K有细微失真
    WebP91.5K16.3K没有失真

    a.背景图选用webp比较划算

    b.小图标选用svg比较划算

    c.对于图标相同只是颜色不同的无需再做图,我们只需要设置着色器android:tint属性就好了,可以省下好些图标空间

    值得提一句:我们写layout布局时,1.可以将公共部分提取出来,2.改用约束布局尽量少一些layout层级。虽然对包体积不是很大,但多多少少会影响一些性能

  4. .dex,该目录是.java文件在Davlik编译的字节码文件,相当于JVM的字节码.class,优化方向有以下几点:

    1.将app目录下build.gradle文件中minifyEnabled设置为true,即代码压缩/代码混淆。这里需要注意的是对于从外部引入的一些三方库,不能够被混淆,需要在proguard-rules定义混淆规则

    2.移除废弃功能的代码,反正有Git,删了代码随时可以找回

    3.提取重复代码

    4.减少不必要的依赖。有时为了某个需求添加依赖,而后删除该需求后需记得删除该依赖

    5.删除重叠框架。例如网络请求框架有okhttp、volley等,协同开发时往往会引入多种网络框架,这时只需保留一种框架

    6.插件化。例如某些不常用的功能,既想拥有小体积,又想保留该功能,这时只需保留接口,通过网络从服务器下载相应功能的插件apk,在主应用中动态加载。关于插件化,我在后面的文章中会做简单介绍

  5. .arsc。它是res的一套关系映射规则,通过以下这张图我们应该清楚知道平时我们代码中使用的R.xxx.xxx其实就是通过这个关系映射找到的
    在这里插入图片描述
    像以上的string资源,默认它会编译出所有语言,如无必要,我们只需编译所需语言即可。此处以中文为例,只需在app目录下build.gradle中加入:resConfigs ‘zh’
    在这里插入图片描述
    代码如下:

    resConfigs "zh"
    

    优化后效果:
    在这里插入图片描述

总结

1.优化方向大致就是以上几点。通过一系列的优化,应用从39.2M优化到了15.6M

2.关于优先级需要大家结合自身项目,根据优化难易程度、可优化幅度等多重因素综合定夺

拓展

1.assets、res之间的异同?

答:异:

  1. assets文件夹下的文件不会被映射到R.java中,res文件夹下的文件会被映射到R.java文件中
  2. assets访问需要AssetManager类,res访问直接使用资源ID
  3. assets可以自定义目录结构,res不可以自定义目录结构(以下情况例外,build.gradle声明)
    在这里插入图片描述
    在这里插入图片描述
    同:两者目录下的文件在打包后会原封不动的保存在apk包中,不会被编译成二进制

2.META-INF有什么用?
在这里插入图片描述
答:META-INF文件夹主要存放的配置信息,签名信息和版本信息,不能在瘦身时删除

上图中可发现CERT.SF,MANIFEST.MF,CERT.RSA和一些依赖包的version:

CERT.SF:

MANIFEST.MF:存放的是版本号,以及每个文件的哈希值,内容形式跟CERT.SF基本一致
在这里插入图片描述
CERT.RSA:签名相关

工具

字体提取工具:1.FontCreator、2.sfnttool

举报

相关推荐

0 条评论