Android 包体积优化建议-资源篇

这是 Android 官方文档给出的一些减少包体积的建议,最近正好在看这方面内容,顺手记录、分享一下。本文主要是针对 Android 的资源(Resource) 相关优化建议。

1 移除无用资源

使用 lint 静态代码分析工具 查找出未使用的 res 资源。

注意 assertlib 下的未使用资源无法检测出来,其中 assert/ 资源引用采用的是反射方法。 除了检测工具外,Gradle 还支持在打包编译的时候自动移除无用资源,使用 shrinkResources

groovy 复制代码
android {
    // Other settings
    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

这里 minifyEnabled 需要一起打开,即代码压缩。这样编译的时候会先用 R8 进行无用代码移除,然后 gradle 插件进行无用资源的移除。详细使用参考:Shrink, obfuscate, and optimize your app

除此之外,还可以使用 resConfig 配置针对指定的 flavor 来打包指定的资源。比如外发包的图片和第一方的包的资源不一样,配置在不同的文件夹下,打包的时候就可以只打包指定的文件夹资源,这样也能减少一定的体积。

2 减少依赖库大小

开发的时候,在选择第三方工具库时,需要关注一下该库的大小。比如 Android 图片加载库 GlidePicassoFresco 的选择,将依赖库的体积大小作为选用的衡量标准之一。

另外,如果只是使用某个工具库的其中一个(小)功能,是否可以考虑将其下载下来自行修改,适当移除不需要的功能代码,从而减少依赖库的体积。

3 原生动画图片支持

使用 ImageDecoder 原生 API 支持带动画的 GIF 和 WebP 的图片文件格式,从而删除第三方库减少包体积。

要求 Android 11 以上才支持

4 支持特定分辨率

从 Android 4.4 开始,支持 ldpi, mdpi, tvdpi, hdpi, xhdpi, xxhdpixxxhdpi 这么多的分辨率(屏幕密度,density),但是没有必要给每个分辨率都制作对应的图片资源。

也许你的用户只有 0.1% 的人需要 ldpi ...

这个时候,其实我们只需要一种分辨率的文件夹,比如 drawable-nodpi/,对于其他的,系统会自动适配(放大缩小)

官方推荐至少有一种分辨率 xxhdpi

5 使用 drawable 或代码渲染图片

有些单色背景图片其实不需要静态的图片文件,使用 Drawable 对象(xml 里的 )可以在运行的时候绘制出来,从而节省出静态图片文件的大小。

对应的,使用代码来生成某些简单的效果图(render from code),比如页面背景设置为纯色。

相比使用图片文件,可以减小一定的包体积大小。

6 复用资源

某些情况下,两张图片可能除了角度或者颜色不一样,其他都是一样的,这个时候,我们就不推荐使用2张图片,可以通过代码来上色或者旋转。

图片的纯上色(改变颜色),大于 Android 5.0(API 21) 的系统可以使用 android:tinttintMode ,小于 Android 5.0 的版本使用 ColorFilter 来完成。

改变图片的旋转角度,比如上箭头改为下箭头这种,使用下面这样即可:

xml 复制代码
<?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" />

7 压缩图片资源文件

官方内置的工具 aapt ,在编译的时候,会自动对 res/drawable/ (其他目录无效,比如 asset/ )里面的图片进行无损压缩(lossless compression),如果不需要,可以手动关闭:

groovy 复制代码
buildTypes.all { isCrunchPngs = false }

需要注意的是,isCrunchPngs 在 release 默认打开(这会增加编译时间),debug 下默认关闭。

选用第三方工具进行不同格式图片压缩:

8 使用 WebP 文件格式

Android 3.2(API 13) 之后开始支持 WebP 图片格式。

WebP 相比 JPEG 和 PNG 有更好的压缩效率(即压缩的体积更多,损失越小),可以直接在 Android Studio 里面将 BMP, JPG, PNG 或者静态 GIF 图片转换为 WebP 格式。

JPEG 为有损压缩(lossy compression) PNG 为无损数据压缩,主要体现在透明度上的变化。(lossless data compression,a raster-graphics file format)

9 使用矢量图形(vector graphics)

矢量图形是一种与分辨率无关的图片,100字节大小的文件可以描述出充满整个屏幕的高清图片。

矢量图形在代码里用 VectorDrawable 表示。

但是有一定的性能问题。矢量图形本质上就是一系列 xml 数据,Android 系统根据矢量图形的"描述"调用 cpu\gpu 去绘制出来一张图:比如x坐标以上涂满红色,y坐标以下涂满绿色,哪里哪里填上灰色...

适合用于小面积的图标(icon)绘制,不适合大面积的图像绘制,有一定的性能消耗。

例子:

ini 复制代码
<!-- res/drawable/battery_charging.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:height="24dp"
    android:width="24dp"
    android:viewportWidth="24.0"
    android:viewportHeight="24.0">

   <group
         android:name="rotationGroup"
         android:pivotX="10.0"
         android:pivotY="10.0"
         android:rotation="15.0" >

      <path
        android:name="vect"
        android:fillColor="#FF000000"
        android:pathData="M15.67,4H14V2h-4v2H8.33C7.6,4 7,4.6 7,5.33V9h4.93L13,7v2h4V5.33C17,4.6 16.4,4 15.67,4z"
        android:fillAlpha=".3"/>

      <path
        android:name="draw"
        android:fillColor="#FF000000"
        android:pathData="M13,12.5h2L11,20v-5.5H9L11.93,9H7v11.67C7,21.4 7.6,22 8.33,22h7.33c0.74,0 1.34,-0.6 1.34,-1.33V9h-4v3.5z"/>
   </group>
</vector>

渲染生成:

还有动画效果也可以使用 vector graphics 来实现,参考 AnimatedVectorDrawableCompat

(对比使用逐帧动画,需要放入大量的单帧图片组合一个动画,极大增加了apk包大小!)

参考

Reduce your app size

相关推荐
随·枫11 分钟前
datalist 是什么?以及作用是什么?
前端
码农小丘28 分钟前
第二章 Spring Boot快速⼊⻔ —— Spring Boot配置文件
java·前端·spring boot
yqcoder43 分钟前
reactflow 中 selectionMode 组件作用
前端·javascript
伏飞而行1 小时前
七、利用CSS和多媒体美化页面的习题
前端·css·html5
GISer_Jing1 小时前
React面试高频核心问题
前端·react.js·面试
我不要放纵2 小时前
通过shell脚本分析部署nginx网络服务
前端·网络·chrome
Mrs_Lupin2 小时前
如何在react中使用react-monaco-editor渲染出一个编辑器
前端·react.js·编辑器
碎像2 小时前
Vue 中的透传,插槽,依赖注入
前端·javascript·vue.js
想你的风吹到了瑞士2 小时前
vue如何实现组件切换
前端·javascript·vue.js
ling-452 小时前
Javaweb-day12(登录认证)
服务器·前端·servlet