appt2
工具会将你的Android应用资源打包成运行时的格式。它同时会生成 ProGuard
或R8
需要的“keep” 规则,因此那些在资源文件中引用的类将不会被移除。一些类的例子如:仅在layout XML文件中引用的View,仅在menu XML文件中引用的 Action Provider 和仅在在AndroidManifest文件中引用的广播接收器,如果没有这些规则,它们将会在最终的APK文件中被删除。
在Android Gradle plugin
3.3.0-alpha05以前的版本,aapt2
会生成针对这些类的构造方法生成一条使用通配符的“keep”规则。一些application、activity、view类的规则如下:
# Referenced at frontend/android/build/intermediates/merged_manifests/release/AndroidManifest.xml:20
-keep class com.jakewharton.sdksearch.SdkSearchApplication { <init>(...); }
# Referenced at frontend/android/build/intermediates/merged_manifests/release/AndroidManifest.xml:28
-keep class com.jakewharton.sdksearch.ui.MainActivity { <init>(...); }
# Referenced at search/ui-android/build/intermediates/packaged_res/release/layout/search.xml:57
-keep class android.support.v7.widget.RecyclerView { <init>(...); }
导出发布APK文件中的方法:
com.jakewharton.sdksearch.SdkSearchApplication <init>()
com.jakewharton.sdksearch.ui.MainActivity <init>()
android.support.v7.widget.RecyclerView <init>(Context)
android.support.v7.widget.RecyclerView <init>(Context, AttributeSet)
android.support.v7.widget.RecyclerView <init>(Context, AttributeSet, int)
SdkSearchApplication
和MainActivity
仅包含一个默认的构造方法,但RecyclerView
却包含三个构造方法。如果仅考虑反射查找的需要,仅需要使用到一个构造方法。在manifest文件中引用的类仅会使用默认无参的构造方法。对于在layout文件中引用的类,仅有它的两个参数(Context
,AttributeSet
)的构造方法会被LayoutInflater
调用。由于生成的规则为<init>(...)
,我们强制保留了所有的构造方法,尽管我们只需要一个。
在Android Gradle plugin
3.3.0-alpha05以后的版本中,新版本的aapt2
被用来生成更精确的规则,这些规则仅保留反射查找所需要使用的构造方法。
# Referenced at frontend/android/build/intermediates/merged_manifests/release/AndroidManifest.xml:20
-keep class com.jakewharton.sdksearch.SdkSearchApplication { <init>(); }
# Referenced at frontend/android/build/intermediates/merged_manifests/release/AndroidManifest.xml:28
-keep class com.jakewharton.sdksearch.ui.MainActivity { <init>(); }
# Referenced at search/ui-android/build/intermediates/packaged_res/release/layout/search.xml:57
-keep class android.support.v7.widget.RecyclerView { <init>(android.content.Context, android.util.AttributeSet); }
现在再次导出发布APK文件中的方法:
com.jakewharton.sdksearch.SdkSearchApplication <init>()
com.jakewharton.sdksearch.ui.MainActivity <init>()
android.support.v7.widget.RecyclerView <init>(Context, AttributeSet)
android.support.v7.widget.RecyclerView <init>(Context, AttributeSet, int)
RecyclerView
的<init>(Context)
构造方法不见了,那个被强制添加到release APK中尽管实际上并没有被使用到的构造方法。三个参数的构造方法仍然被保留,因为两个参数的构造方法会调用到它。
public RecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
如果开启优化选项并且没有其他规则使用到三个参数的构造方法,那么它将可能被内联,这个是在旧的规则中不可能发生的。
这看起来是一个比较小的变化,并且大部分情况下Application、activity和action provider子类型通常都仅包含一个构造方法,因此他们的计数好像没有变化。然而View的子类通常会有三个或者四个的构造方法,并且现在你将看到两到三个的构造方法被移除了。而在整个APK的范围内,将会有数十到上百个不在需要的方法被删除。由于特殊“keep”规则的增加,不仅是减少最终APK中原始的方法数,还使得优化器有更好的执行效果。