Android优化——proguard之缩减体积

2024-01-15 16:32

本文主要是介绍Android优化——proguard之缩减体积,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • Android Proguard
    • 代码压缩(code shrinking)
      • 原理
      • 测试
      • 自定义保留类
    • 资源压缩(Resource Shrinking)
      • 自定义保留资源
      • 严格引用检查
      • 资源压缩测试
      • 移除重复资源
      • 合并(merge)重复资源

Android Proguard

为了尽可能减小应用的大小,应该启用缩减功能来移除不使用的代码和资源。启用缩减功能后,您还会受益于两项功能,一项是混淆处理功能,该功能会缩短应用的类和成员的名称;另一项是优化功能,该功能会采用更积极的策略来进一步减小应用的大小。

代码压缩(code shrinking)

R8工具的代码压缩功能在配置minifyEnabled值为true后就默认打开了。

代码压缩(code shrinking)是R8工具移除在运行时不需要使用的代码过程。这个过程中R8移除不需要的类,变量,方法等。

原理

R8先根据配置的proguard文件(默认,或自定义),分析确定代码的切入点。Android会依据这些切入点打开Activity或者Service。从每个入口点开始,R8会分析并构建包含类,变量,方法和其他在运行时可能访问到的类的图。而未分析到的类会被认定是不可达的,在后续打包过程中将被移除。

在上图中显示了App运行时以来的库,R8在分析后将MyActivity.class作为入口,确定方法foo()faz(),以及AwesomeApi.class的方法bar()是可达的。而OkayApi.class类是不可达的,因此在打包压缩过程中会被移除。

R8依据proguard文件内的-keep规则确认切入点。-keep规则指定的class文件是R8在压缩代码时不能移除的,并且将保留作为App的切入点。

测试

module目录下的build.gradle文件内配置minifyEnabled值为true后,程序代码压缩功能就默认打开了,在打包release版本过程中,Android打包工具会源码进行压缩,移除其中不使用的类,变量,方法等,从而达到缩小最终APK体积的目的。

配置minifyEnabled值后体积大小对比如下图——第一张图minifyEnabled=true,第二张图minifyEnabled=false

自定义保留类

默认的ProGuard规则(proguard-android-optimize.txt)对R8在压缩代码过程中移除不需要的代码已经足够。

但也有R8会错误移除的个别情况:

  • 调用JNI(Java Native Interface)接口;
  • 调用反射接口;

测试过程中可以揭露由于错误移除导致的错误,但是也可以通过配置产生一个report文件查看移除与保留的类。

怎么解决错误移除问题呢? 使用-keep规则,例如

-keep public class MyClass

也可以使用@Keep标注解决上述问题。@Keep标注在类声明上面,该类会保持原有类名及内部结构,不会被压缩处理。

注意:使用@Keep,前提是使用AndroidX Annotation Library标注库。

资源压缩(Resource Shrinking)

资源压缩(Resource Shrinking)与代码压缩(Code Shrinking)一同进行。在代码压缩执行完成,移除无用代码后,资源压缩就也可以确定哪些资源是不再被使用的(反之,明确哪些资源是继续被使用的)。

通过在module目录下的build.gradle文件中设置shrinkResourcestrue,打开该功能,配置代码如下:

android {...buildTypes {release {shrinkResources trueminifyEnabled trueproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}}
}

再设置此项值前,确认是否设置了minifyEnabled,如还未设置,可以先设置这项来打开代码压缩功能。

自定义保留资源

若希望保留/丢弃某些特殊资源,可以在一个xml文件中进行配置。
xml文件中根标签是 <resources>,在 tools:keep 属性下配置需要保留的资源,在tools:discard属性下配置要丢弃的资源。

并将配置文件命名为 keep.xml 保存在raw目录下res.raw/keep.xml

<?xml version="1.0" encoding="utf-8"?>  
<resources  xmlns:tools="http://schemas.android.com/tools"  tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*"  tools:discard="@layout/unused2"  />

构建工具不会将此文件打包到APK文件中。

明确要移除的资源,可能会被说还不如直接删除更加直接。但是在使用构建变量时,这是很有用的。例如,在project资源文件夹中有众多资源,且为不同的构建变量创建不同的keep.xml文件。此时,对于已知的构建变量,知道需要使用的资源。

严格引用检查

如果使用了Resources.getIdentifier()(或者库中使用了——AppCompat库使用了),这意味着代码需要依据动态生成的字符串进行资源搜索。这样R8在资源压缩时会认定动态生成的字符串资源名开始的所有资源文件可能会被引用,因此不会进行移除。

例如:

val name =  String.format("img_%1d", angle +  1)  
val res = resources.getIdentifier(name,  "drawable", packageName)

代码中,资源名是动态生成的,因此R8会认定所有以img_开始的资源会被引用,因此一些即便不被使用,但是名字以img_开始的资源文件不会被移除。

同样,资源压缩器会分析代码中的字符串常量,以及/res/raw/目录下各种资源,类似file:///android_res/drawable/ic_plus.png的URL地址。如果压缩器检查到类似这些地址或资源,或者看起来可以组成类似的URL地址的资源,压缩器不会移除这些资源。

以上这些均是在默认的safe模式下的资源压缩。

另外一种即是strict模式,需要在raw目录下的keep.xml内配置strict值。

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"tools:shrinkMode="strict" />

这样凡是未被R8认为被引用的资源将被移除。

资源压缩测试

在project中有资源airplane_space.png的图片资源,在layout目录下保留有不被引用的fragment xml文件。

代码如下:

    val name = "airplane_space"findViewById<AppCompatButton>(R.id.button_get_identifier_res).setOnClickListener {val resID = resources.getIdentifier(name, "mipmap", packageName)findViewById<AppCompatImageView>(R.id.image_ret).setImageResource(resID)}

这里在运行时使用getIdentifier()来获取资源id。打release包。

在打release包前,还需要搞清楚一个问题,即资源压缩在默认情况下是safe模式下,另外一个是strict模式。这种模式下是资源压缩处理是不同的。


下面来看下两种模式下不同的资源表现

  1. layout文件

    • safe mode

      上图是在safe模式的资源压缩下,在打包过程中列出的未使用布局文件资源(unused resource)。这里可以看出,被处理的是系统文件,App下的布局文件未被处理。
      也可以通过反编译,查看到,未被使用的布局文件内容未被处理。

    • strict mode
      unremoved
      上图中显示的是strict模式的资源压缩下,针对App内未被引用的fragemnt xml文件进行的处理。可以看到括弧内提示,原有文件内容被104字节内容替换掉了(replaced with small dummy file of size 104 bytes)。
      也就是文件没有被移除,但是文件内容被替换成了固定大小(104字节)内容。在反编译后,打开被处理过的xml文件,固定内容如下:

      <?xml version="1.0" encoding="utf-8"?>
      <x />
      
  2. 图片资源

    • safe mode
      safe模式下,使用运行时代码动态加载的图片资源未被移除。

    • strict mode
      strict模式下,图片资源的会被移除,与布局资源文件一样,图片文件依然存在,但内容已经被替换。

如果要在strict资源压缩模式下,保留动态加载的图片不被处理,需要在/res/raw/keep.xml中使用tools:keep来设置需要保留的资源。

这次的测试的保留图片资源,设置带代码如下。

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"tools:shrinkMode="strict"tools:keep="@mipmap/airplane_space"/>

移除重复资源

资源压缩器只会移除不被code引用的资源,也就意味着可能因为设备配置的不同导致可选资源被移除。例如,多语言apk中会包含有多种语言的string字符串资源,但在很多情况下只需要其中一种或若干种语言翻译,此时其他的语言种类可以移除。这种情况下,可以使用gradle的resConfig类配置需要保留的资源包,其他未配置的语言包将被移除。

android {defaultConfig {...resConfigs "en", "fr"}
}

类似的可以配置不同的分辨率设备,以及不同的ABI配置的资源。

合并(merge)重复资源

Gradle在一般情况下会合并在不同资源目录下的同名资源文件,例如在不同drawable目录下的资源。这个合并过程不是通过shrinkResources配置项控制的,也不能停止,因为代码运行时在多个资源中寻找匹配的资源可以避免错误的发生。

当两个或更多资源共有相同的名字,类型,及限定名情况下,会发生资源合并。Gradle会在多个重复资源之间选择最合适的资源,传递给AAPT进行编译并发布。

Gradle在以下位置中搜索资源:

  • src/main/res/目录下的主要资源。
  • 变量覆盖,基于构建类型(build type)与渠道设置(build flavors)。
  • 依赖库中资源。

Gradle按照一下优先级顺序合并资源顺序: Dependencies -> Main -> Build flavor -> Build type

举个栗子,在main资源和build flavor中都有一个相同的资源,Gradle在构建时会选择build flavor中的资源。

如果在同意源码集中出现同名资源,Gradle不会合并,且会抛出错误。例如在build.gradle中设置sourceSet属性,使得在src/main/res/src/main/res2/目录下包含相同资源。

这篇关于Android优化——proguard之缩减体积的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/609514

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

HDFS—存储优化(纠删码)

纠删码原理 HDFS 默认情况下,一个文件有3个副本,这样提高了数据的可靠性,但也带来了2倍的冗余开销。 Hadoop3.x 引入了纠删码,采用计算的方式,可以节省约50%左右的存储空间。 此种方式节约了空间,但是会增加 cpu 的计算。 纠删码策略是给具体一个路径设置。所有往此路径下存储的文件,都会执行此策略。 默认只开启对 RS-6-3-1024k

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

MySQL高性能优化规范

前言:      笔者最近上班途中突然想丰富下自己的数据库优化技能。于是在查阅了多篇文章后,总结出了这篇! 数据库命令规范 所有数据库对象名称必须使用小写字母并用下划线分割 所有数据库对象名称禁止使用mysql保留关键字(如果表名中包含关键字查询时,需要将其用单引号括起来) 数据库对象的命名要能做到见名识意,并且最后不要超过32个字符 临时库表必须以tmp_为前缀并以日期为后缀,备份

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk