shrinkResources去除无用资源原理

开启shrinkResources后,打包过程会新增task transformClassesWithShrinkResFor{variant},gradle1.5之后只需要注册一个tranform就会产生一个对应的task,查看源码发现对应的tranfrom在com.android.build.gradle.internal.transforms.ShrinkResourcesTransform,此类中调用com.android.build.gradle.tasks.ResourceUsageAnalyzer的analyze方法进行分析无用资源。

 

ResourceUsageAnalyzer:

该类的开头有这么一段话:

我翻译一下这段:

这个类负责搜索一颗gradle构建树(在合并资源,编译,压缩已经完成之后,最终的apk组装之前),这颗构建树确定了那些资源是未使用的,并将其删除。

它通过检查做到这一点:

  • 合并的清单,用于查找根资源引用(例如启动图标)
  • 合并的R类(查找分配给资源的实际整数常量)
  • 混淆映射文件(找到原始名称到混淆后短名称的一个映射)
  • 合并的资源(用于查找哪些资源引用其他资源,例如包括其他other drawables的drawable state lists,或包括其他布局的布局,或引用其他drawables的styles,或包括布局文件的菜单项等)
  • 缩小的输出类(在代码中查找实际可访问的资源引用)

所有的这些,构建了一个引用图,并基于根引用(例如来自清单与剩余代码),它计算出了在app中哪些资源是实际可达的,然后将任何无法访问的内容标记为删除。

如果文件R.type.name被引用(非最终资源引用,例如在库中),或者在代码中引用相应的int值,我们通过ASM查看输出的代码来检查这一点。有一个复杂的问题是代码可以通过Resources#getIdentifier(String,String,String),通过传递资源的名称去查查找资源,为了处理这种情况,我们使用ClassVisitor来查看是否有对特定Resources#getIdentifier方法的任何调用如果没有,很好,使用分析是完全准确的。如果我们找到一个,我们检查 所有在应用程序中的任何位置找到的字符串常量,并查看是否有看起来有关。例如,如果我们找到字符串“string / foo”或“my.pkg:string / foo”,我们将标记名为foo的字符串资源(如果有)作为可能使用的字符串资源。

 

 一:

 

 SdkConstants.FN_RESOURCE_CLASS = R.java

可以看出它找到的是R.java文件,然后调用parseResourceClass(file);方法,将R.java中的资源都标记为可达,加入表中。

 

recordMapping(mProguardMapping)

解析混淆文件,将现在的把映射存于表中

 

 

 

recordManifestUsages(mMergedManifest);

分析Manifest文件,将找到的引用标记为可达,例如:启动图标

 

发布者

大道苍莽,一笔一墨,皆重之。

发表评论

电子邮件地址不会被公开。