首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >优化| APK瘦身最佳实践

优化| APK瘦身最佳实践

作者头像
开发者技术前线
发布2020-11-23 15:30:26
9310
发布2020-11-23 15:30:26
举报

APK瘦身也是anroid领域比较关注的技术之一,在开始对APK进行正式的减肥之前,我们先来了解一下APK包的构成,这样才好对症下药嘛。知己知彼方能百战不殆。

APK文件内容速揽

我们可以通过 unzip <apkname>.apk 命令实现对apk的解压(你也可以直接将<apkname>.apk更名为<apkname>.zip后直接通过解压软件解压)。解压后,我们就会得到一个文件夹了,里面包含了:

AndroidManifest.xml/assetsclasses.dex
classes2.dex.../lib
    /arm64-v8a
    /armeabi-v7a
    /mips
    /x86
    /x86_64/META-INF
    CERT.RSA
    CERT.SF
    MANIFEST.MF/res
    /anim
    ...resources.arsc

各个文件和目录的作用是什么呢?

文件/目录

作用

OK,既然我们已经了解了APK的各个组成部分,那么我们就可以针对下面的三个组成部分,采取逐个击破的方式,达到缩减APK体积的目的:

  • Java代码
  • 资源文件
  • Native Code
  • 其他

Java代码

我们可以使用Proguard,在编译时对Java代码进行混淆,优化和压缩。Proguard对代码进行遍历,然后剔除其中未被使用的冗余的代码,并对类,属性,接口等进行重命名,从而达到瘦身的目的。

我们可以在 build.gradle 文件中配置Proguard。

buildTypes {

        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }

    }

在未使用Proguard之前,我们的APK体积达到了13.9M。

开启Proguard后,APK的体积缩减到了10.1M。可见,效果还是很明显的。

除此之外,微信的工程师还开源了一个项目,可以直接对APK进行处理,缩小体积。具体的使用方法:https://github.com/shwenzhang/AndResGuard。

资源文件

Lint

由于Proguard只对Java代码起作用,对于资源文件,它就无能为力了。这个时候,Lint就派上用场了。Lint是一个静态的代码分析器,我们可以通过在 Android Studio -> Analyze -> Inspect code... , 选择范围即可开始就检查。

Lint在检查完成后,会提供一份详细的资源文件清单,并且将没有用到的资源在 UnusedResources:Unused resources 区域。只要我们没有通过反射使用这些资源,就可以放心的删掉它们了。

下面是我根据lint的提示,剔除了部分无用资源后,APK的体积:

Notice:需要注意的是,Lint并不会扫描 assets 目录,所以最好还是手动的检查一下 assets 目录下是否有未被使用的文件吧。

我们还可以通过配置 shrinkResources 来移除未使用的资源。不过,使用 shrinkResources 必须开启代码混淆。在处理过程中,ProGuard 会移除未被使用的代码,但是不会移除资源。而开启 shrinkResources 后,Gradle就会移除资源了。

下面为开启 shrinkResources 后APK体积的变化:

又缩小了一点点。

图片压缩

对于资源文件的优化,其实占大头的还是图片。Android打包本身会对png进行无损压缩,在不那么影响图片显示效果的情况下,对图片进行有损压缩对apk体积的减小还是非常可观的。

我们先使用TinyPng对项目中四张比较大的图片进行压缩,可以看出,效果还是非常不错的。

使用TinyPng后,我们还可以将图片转换为 WebP 格式,进一步缩小图片的体积。不过需要注意的是,WebP格式仅适用于Android 4.0+版本,如果你的应用需要兼容Android 2.3,那么需要额外的引入 .so 文件,apk的体积自然也会增加。所以,根据你的需求,权衡利弊吧。

Android Studio 中,选定需要转换的图片,然后右键鼠标,即可在菜单底部看到 Convert to WebP 的选项了,然后就可以进行转换的操作。

经过上面的处理,我们的App体积来到了9.6M。

矢量图

如果你的项目中使用 appcompat 兼容包,并且版本在23.2以上,那么,使用矢量图或许是个不错的选择。矢量图和分辨率无关,理论上支持任何级别的缩放。以一张常用的 点赞 图标为例,在 Android中使用 Vector 矢量图,大小为:

而它对应的xxxhdpi的png格式,大小为:

效果显而易见,但是这也并不是意味着,我们就可以将所有的图片替换为 矢量图 了 。我们来看一看 ic_favorite_black_24dp.xml 的源代码:

<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="24dp"
        android:height="24dp"
        android:viewportWidth="24.0"
        android:viewportHeight="24.0">
    <path
        android:fillColor="#FF000000"
        android:pathData="M12,21.35l-1.45,-1.32C5.4,15.36 2,12.28 2,8.5 2,5.42 4.42,3 7.5,3c1.74,0 3.41,0.81 4.5,2.09C13.09,3.81 14.76,3 16.5,3 19.58,3 22,5.42 22,8.5c0,3.78 -3.4,6.86 -8.55,11.54L12,21.35z"/></vector>

正如你所见,vector的颜色是单一的颜色,所以,vector 适用于图标等颜色单一的图片,如果是颜色比较复杂,那么vector很明显就不合适了。

使用JPG

对于非透明的大图,JPG格式将会比PNG格式的大小有显著的优势,虽然不是绝对的,但是通常会减小到一半都不止。在启动页,活动页等之类的大图展示区采用JPG将是非常明智的选择。

对于图片的使用,Google的建议,简单来说就是:VD->WebP->Png->JPG

  • 如果是纯色的icon,那么用svg
  • 如果是两种以上颜色的icon,用webp
  • 如果webp无法达到效果,选择png
  • 如果图片没有alpha通道,可以考虑jpg
复用图片

项目中我们还可能遇到图片内容相同,仅仅是颜色不同的情况。这个时候我们就可以使用Android提供的着色来完成,而不用提供好几套图片。例如在Android 5.0+上我们可以使用 android:tintandroid:tintMode,在低版本中可以使用 ColorFilter

对于那些内容颜色等都相同,只是方向不同的图片,我们可以只保留一中方向的,其他方向的图片通过代码实现。例如我们可以对上面提到的 ic_favorite_black_24dp 进行翻转。创建一个 drawable

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

虽然Android设备的分辨率非常的多,但这并不代表着我们需要为每一种分辨率都准备一套资源。在显示差异不大的情况下,我们可以尽量复用一套图片资源,一套布局,然后再考虑特定屏幕密度。

语言资源

说完了图片,我们还要来说说语言资源。对于大多数的应用,并不需要支持几十种的国际化。使用Gradle,对语言资源进行配置,也可以达到应用瘦身的目的。例如,我们的应用如果只需要支持中文和英语:

android {
    defaultConfig {
        ...
        resConfigs "en", "zh"
        // 支持分辨率
        resConfigs "nodpi", "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"
    }
}

Native Code

如果你的App使用到了Native code,在不影响功能的前提下,可以考虑去除部分平台对应的代码,例如移除对 armeabi、mips的支持。

android {
    ... 
    splits {
        abi {
            enable true
            reset()
            include 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
            universalApk true
        }
    }

 }

当然,如果是特别大的原生库,我们还可以通过网络,从云端获取,而不直接打包在APK中。

其他

  • 别忘了最简单,也最容易忽视的,去除重复的依赖,或者是引用更加轻量级的库,也可以达到apk瘦身的效果。
  • 在Release版本中,去除那些只会在debug时才会出现的代码。
  • 对于那些使用频率很小的文件或者是图片,可以存放到云端后,通过网络加载。

结语

相对小的体积能够在用户安装前就给用户留下不错的印象,但是,这不并代表着我们可以为了追求APK体积的小巧而过度的牺牲用户体验。权衡利弊后,选择合适的,才是最重要的。

项目完整地址:https://github.com/TonnyL/Espresso

Espresso is an express delivery tracking app designed with Material Design style, built on MVP(Model-View-Presenter) architecture with RxJava2, Retrofit2, Realm database and ZXing.

作者:TonnyL 链接:http://www.jianshu.com/p/f6b96a25362f

iOS打赏通道

精彩推荐

为了钱就别选择当程序员

技术 - 资讯 - 感悟

END

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-08-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 开发者技术前线 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • APK文件内容速揽
  • Java代码
  • 资源文件
    • Lint
      • 图片压缩
        • 矢量图
          • 使用JPG
            • 复用图片
              • 语言资源
              • Native Code
              • 其他
              • 结语
              相关产品与服务
              图片处理
              图片处理(Image Processing,IP)是由腾讯云数据万象提供的丰富的图片处理服务,广泛应用于腾讯内部各产品。支持对腾讯云对象存储 COS 或第三方源的图片进行处理,提供基础处理能力(图片裁剪、转格式、缩放、打水印等)、图片瘦身能力(Guetzli 压缩、AVIF 转码压缩)、盲水印版权保护能力,同时支持先进的图像 AI 功能(图像增强、图像标签、图像评分、图像修复、商品抠图等),满足多种业务场景下的图片处理需求。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档