技术

如何进行APK瘦身

2018-07-03  本文已影响158人  ming152

本篇文章已授权微信公众号guolin_blog(郭霖)独家发布

转载请注明出处:https://www.jianshu.com/p/7b623fed6302

APK的大小对于app载入速度、占用内存大小以及耗电量有着很大的影响。一般而言,用户并不太喜欢下载APK体积太大的app。尤其是对于流量、手机内存有限的用户来讲,太大的APK往往会让他们望而却步。那么如何让APK的体积降下来呢?

了解APK结构

想要对APK进行瘦身,你必须得先了解APK的组成结构,只有了解APK由哪些部分组成,你才能有所针对性的进行APK瘦身。
APK主要由以下几部分组成:

我们可以通过android studio --> build --> Analyze APK 来查看一下上述各个部分文件大小情况

analyze.png
从上图来看,占用空间的主要是代码、res 和 lib ,因为我的assets中没有放文件,所以看起来并没有占用什么空间,其实assets中文件放的多,一样会占用很大空间。所以APK瘦身时,主要就从代码reslibassets这几个方面考虑。

减少资源文件数量和大小

APK瘦身的一个很简单的办法就是减少资源文件的数量和大小,本节就来讨论一些常用的方法。

去除无用资源
android {
    // Other settings

    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}
android {
    defaultConfig {
        ...
        resConfigs "zh"
    }
}
使用最小化资源的库

我们开发项目的时候,经常会用到许多第三方库,但第三方库往往可能会很大,那怎么来进行压缩呢?

只支持特定屏幕密度

Android支持多种屏幕密度设备,Android 4.4以上版本支持包括:ldpi, mdpi, tvdpi, hdpi, xhdpi, xxhdpi and xxxhdpi。尽管Android支持了这么多屏幕密度,但你并不需要全部支持,你可以根据你的需求来选择支持。

使用drawable 对象

对于一些简单的images可以不使用图片,使用Drawable XML来进行绘制。

复用资源

对于相似的一些Image可以复用同一张图片。

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_thumb_up"
    android:pivotX="50%"
    android:pivotY="50%"
    android:fromDegrees="180" />
代码渲染

你也可以通过代码渲染来代替使用图片,例如使用自定义View绘制。图片减少了,APK自然瘦身了。

紧缩PNG文件

AAPT工具会在构建期间自动对res/drawable/文件夹下的PNG图片资源做无损压缩。例如,一张true-color的PNG图片,如果它实际需要的颜色不大于256种,那么就有可能会被转换成一张8位的调色板图片(PNG8)。转换之后的图片质量未减却只占用更小的内存。

压缩PNG和JPG

你可以使用pngcrush, pngquantzopflipng来压缩PNG图片。
使用packJPGguetzli 来压缩JPG图片。

使用WebP

你可以使用 WebP 来代替JPG和PNG图片。WebP 保留了JPG和PNG优点的同时,能提供更好的压缩,达到更小的体积。
你可以将已经有的JPG、PNG、GIF等直接转为WebP图片,方法请参考:Create WebP Images Using Android Studio.

注意:启动图标最好不要用WebP,因为谷歌商店只接受启动图片格式为PNG的APK。

使用矢量图形

你可以使用矢量图形来绘制分辨率无关图标及其他可伸缩媒体文件。整个屏幕那么大的清晰图片,如果使用矢量图可能只需要100-byte大小。
然而使用矢量图形会让系统花更多的时间来进行绘制,所以最好只在比较小的images上使用矢量图。

将矢量图形用于动画图像

不要使用AnimationDrawable来创建帧动画,否则每一帧就用一张图片会占用大量的空间。这个时候你应该使用AnimatedVectorDrawableCompat

减少本地代码和Java代码

这儿有几种方法来减小Java代码和本地代码库的大小。

删除不必要的生成代码

要确保能够了解自动生成的代码用途,例如有很多的protocol buffer tools会自动生成大量你可能用不到的代码。

避免使用枚举

一个单独的枚举可以将apk增加1.0 到1.4 KB大小,对于复杂的系统或者共享库来说,累积下来可能会增加相当大的APK体积。
如果可能的话,可以考虑使用@IntDef注解和ProGuard来剥离枚举并将它们转换为整数。这种类型转换保留了枚举的类型安全优势。

减少本地二进制文件的大小

如果你的APP使用native code 和 Android NDK,那么可以通过两种方法优化代码,达到减小APK大小的效果。

<application
 android:extractNativeLibs=”false”
 ...
>

该属性告诉系统,不要把 so 文件从 apk 中解压出来了,并且修改 System.loadLibrary 调用直接从 apk 中打开 so 文件。

维护多个精简版APK

你的APP中可能会包含许多用户根本不会使用的内容,例如区域和语言信息。你可以根据屏幕尺寸或GPU纹理支持等因素针对性提供不同版本的APK。当用户下载APK的时候,会根据手机的特性和设置有针对性的下载特定版本APK,这样的话用户就不会下载到他根本不需要的内容。
上面的话是从官网翻译过来的,看不太懂没关系,其实就是按需提供资源支持,根据手机的不同提供不同版本的APK,我们直接来看例子

android {
  ...
  splits {
    //根据屏幕像素密度来创建多个APK
    density {
      enable true
      //根据屏幕密度创建两个版本APK,"mdpi", "hdpi"
      reset()
      include "mdpi", "hdpi"
    }
    //根据手机cpu指令集分类创建多个APK
    abi {
      enable true
      //创建 "x86", "x86_64"两个版本APK
      reset()
      include "x86", "x86_64"
    }
  }
}

我们来编译一下APK看下结果

multipleApk.png
我们可以看到生成了6个APK,为什么是6个呢?
首先屏幕密度有三个版本(mdpi, x86_64,gralde还会生成一个包含所有屏幕密度资源的默认版本),ABI指令集有两个版本(gralde默认编译不会添加包含所有ABI指令集版本的APK,如果你想添加,需要在abi代码块中加上universalApk true),它们两两组合为6种。每个APK里只会包含它对应的资源,例如app-hdpiX86-debug.apk中只会存在屏幕密度为hdpi的资源以及X86的库文件。
如果你的手机cpu指令集是x86,屏幕密度为hdpi,那么你会下载到app-hdpiX86-debug.apk

你可以通过Configure APK SplitsMaintaining Multiple APKs来进一步了解相关内容。

参考资料
https://developer.android.google.cn/topic/performance/reduce-apk-size
https://developer.android.google.cn/studio/build/shrink-code
https://developer.android.google.cn/studio/write/lint
https://www.jianshu.com/p/0eae3f13dcd6
http://blog.chengyunfeng.com/?p=895

上一篇下一篇

猜你喜欢

热点阅读