起因
2020-04-13上班遇到一个问题,应用引用的第三方so库、jar包和初始化java代码,在不同的车机上有差异,我很自然地想到,Gradle的productFlavor应该可以处理,但尝试了一天都没有成功,就放弃了。
有点不服气,决定看一看Gradle的源码。因为我对Gradle的了解特别少,就只能硬看,边看边猜,不一定保证对。但如果不记录下来,很快就会忘记的。
入口
查资料发现,build.gradle中的android应该在,
META-INF/gradle-plugins/com.android.application.property
implementation-class=com.android.build.gradle.AppPlugin
class AppPlugin extends AbstractAppPlugin {
@Override
@NonNull
protected Class<? extends AppExtension> getExtensionClass() {
return BaseAppModuleExtension.class;
}
}
public abstract class AbstractAppPlugin extends BasePlugin<AppExtensionImpl> {
@NonNull
@Override
protected BaseExtension createExtension(...) {
return project.getExtensions()
.create("android", getExtensionClass(), ...);
}
}
这里的createExtension()就是把gradle文件中的android读取并解析成getExtensionClass()对应的对象,在application类型的工程中就是BaseAppModuleExtension对象,而在lib类型的工程中,则是LibraryExtension。
META-INF/gradle-plugins/android-library.property
implementation-class=com.android.build.gradle.LibraryPlugin
public class LibraryPlugin extends BasePlugin<LibraryExtensionImpl> {
@NonNull
@Override
protected BaseExtension createExtension(...) {
return project.getExtensions()
.create("android", getExtensionClass(), ...);
}
@NonNull
protected Class<? extends BaseExtension> getExtensionClass() {
return LibraryExtension.class;
}
}
根据工程类型的不同,android实际对应的类也不同。
暂时不管library, 继续看application,BaseAppModuleExtension类:
open class BaseAppModuleExtension(...): AppExtension(...) {
var dynamicFeatures: MutableSet<String> = mutableSetOf()
val bundle: BundleOptions...
fun bundle(action: Action<BundleOptions>)...
}
看内容应该是新出的App Bundle,还没了解过相关内容,跳过,去看父类AppExtension
public class AppExtension extends TestedExtension {
private final DefaultDomainObjectSet<ApplicationVariant> applicationVariantList
= new DefaultDomainObjectSet<ApplicationVariant>(ApplicationVariant.class);
public DomainObjectSet<ApplicationVariant> getApplicationVariants() {
return applicationVariantList;
}
@Override
public void addVariant(BaseVariant variant) {
applicationVariantList.add((ApplicationVariant) variant);
}
}
现在出现两个问题:
- ApplicationVariant是什么
- DomainObjectSet是什么
Q1 ApplicationVariant是什么
对于问题1,我查到了一段代码,用于定义打包APK时的文件名:
// 没有用lambda, 直接用接口, 方便理解
applicationVariants.all(new Action<ApplicationVariant>() {
@Override
void execute(ApplicationVariant applicationVariant) {
applicationVariant.outputs.forEach(new Consumer<BaseVariantOutput>() {
@Override
void accept(BaseVariantOutput baseVariantOutput) {
println "baseVariantOutput.baseName = ${baseVariantOutput.baseName}"
println "baseVariantOutput.dirName = ${baseVariantOutput.dirName}"
println "baseVariantOutput.name = ${baseVariantOutput.name}"
baseVariantOutput.outputFileName = "Hello_${applicationVariant.buildType.name}_Time.apk"
// println "baseVariantOutput.class.name = ${baseVariantOutput.class.name}"
println "baseVariantOutput.outputFileName = ${baseVariantOutput.outputFileName}"
}
})
}
})
baseVariantOutput.baseName = debug
baseVariantOutput.dirName =
baseVariantOutput.name = debug
baseVariantOutput.baseName = release
baseVariantOutput.dirName =
baseVariantOutput.name = release
baseVariantOutput.class.name = com.android.build.gradle.internal.api.ApkVariantOutputImpl_Decorated
baseVariantOutput.outputFileName = Hello_debug_Time.apk
baseVariantOutput.outputFileName = Hello_release_Time.apk
public interface BaseVariantOutput extends OutputFile {
ProcessAndroidResources getProcessResources();
TaskProvider<ProcessAndroidResources> getProcessResourcesProvider();
ManifestProcessorTask getProcessManifest();
TaskProvider<ManifestProcessorTask> getProcessManifestProvider();
Task getAssemble();
String getName();
String getBaseName();
String getDirName();
// interface OutputFile extends VariantOutput
File getOutputFile();
// interface VariantOutput
String getOutputType();
Collection<String> getFilterTypes();
Collection<FilterData> getFilters();
OutputFile getMainOutputFile();
Collection<? extends OutputFile> getOutputs();
}
跟这段代码时有个地方很疑惑,baseName, name, dirName, 这三个变量可以直接点出来,但outputFileName不行,BaseVariantOutput一路查看父类,都没有发现这个变量,它是从哪里冒出来的。直到我打印了它的class:ApkVariantOutputImpl的父类BaseVariantOutputImpl中定义了outputFileName.setter/getter。
打印ApplicationVariant的实现类,是 : com.android.build.gradle.internal.api.ApplicationVariantImpl_Decorated,同样的参数ApplicationVariant只是个接口,buildType定义在实现类中。
这样的语法实在太反Java直觉了,跟代码的时候特别艰难。
同时也看到了,applicationVariant.buildType=release/debug,而它们就是
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
// debug {} 是默认的
// internal {}
}
如果在buildTypes中定义其他的类型比如internal,那段遍历代码也会把它打印出来。
暂时先不管自定义,默认的debug是怎么默认添加的?实现方式是碰巧看到的 :
ApplicationVariantFactory
@Override
public void createDefaultComponents(
@NonNull NamedDomainObjectContainer<BuildType> buildTypes,
@NonNull NamedDomainObjectContainer<ProductFlavor> productFlavors,
@NonNull NamedDomainObjectContainer<SigningConfig> signingConfigs) {
// must create signing config first so that build type 'debug' can be initialized
// with the debug signing config.
signingConfigs.create(DEBUG);
buildTypes.create(DEBUG);
buildTypes.create(RELEASE);
}
called by BasePlugin:
private void configureExtension() ->
private void basePluginApply(@NonNull Project project) ->
public final void apply(@NonNull Project project) | 入口
最初的AbstractAppPlugin.createExtension()就是在这个apply()方法中被调用,作为插件添加到工程中。
可以看到,signingConfigs也指定了默认debug值,这就是为什么:debug模式下可以直接运行,release模式不可以运行,因为默认没有配置签名工具。
此时又出现一个新问题,NamedDomainObjectContainer是什么东西?Gradle的这些类继承关系有点乱,不过它和DomainObjectSet都是亲戚关系,就把它放在Q2一起查。
Q2 DomainObjectContainer的一大堆子类
public interface DomainObjectCollection<T> extends Collection<T> {
// 根据类型创建一个实例
<S extends T> DomainObjectCollection<S> withType(Class<S> type);
<S extends T> DomainObjectCollection<S> withType(Class<S> type, Action<? super S> configureAction);
<S extends T> DomainObjectCollection<S> withType(Class<S> type, Closure configureClosure);
DomainObjectCollection<T> matching(Spec<? super T> spec);
DomainObjectCollection<T> matching(Closure spec);
// 从名字看上去像添加/删除时的回调
Action<? super T> whenObjectAdded(Action<? super T> action);
void whenObjectAdded(Closure action);
Action<? super T> whenObjectRemoved(Action<? super T> action);
void whenObjectRemoved(Closure action);
// 遍历执行Action/闭包
void all(Action<? super T> action);
void all(Closure action);
// 找出所有符合条件的对象
Collection<T> findAll(Closure spec);
}
withType方法暂时没找到哪里有调用,从其他几个方法可以猜出,它其实就是对Collection做了封装,比如子类public interface DomainObjectSet<T> extends DomainObjectCollection<T>, Set<T>表示它想封装的Collection是Set,不希望有重复值。 NamedDomain 就是比 Demain 多了Namer, 简单猜一下就是根据这个namer对应build.gradle中的配置项名字。
public interface NamedDomainObjectContainer<T> extends NamedDomainObjectSet<T> {
T create(String name);
...
}
public interface NamedDomainObjectCollection<T> extends DomainObjectCollection<T> {
Namer<T> getNamer();
...
}
println "android.buildTypes.class.name = ${android.buildTypes.class.name}"
android.buildTypes.class.name = org.gradle.api.internal.FactoryNamedDomainObjectContainer_Decorated
NamedDomainObjectContainer.create(name) 倒是在前面的 createDefaultComponents() 看到有调用,可惜在源码里找不到这个实现类,看不到具体是怎么实现的,不过可以猜得出来:
此处的泛型表示它想维护一个T类型对象的列表,create(name) 则会根据参数name去生成新T对象并添加到列表中。
比如 buildTypes.create("debug") 会创建一个 名字是debug的BuildType,在build.gradle.buildTypes中自定义一个internal时,猜测最终也是通过 buildTypes.create("internal") 创建一个 名字是internal的BuildType 。
下一篇
接下来看 AppExtension extends TestedExtension父类