1.項目添加 android gradle plugin 依賴
compile com.android.tools.build:gradle:3.0.1
通過這種方式,可以直接依賴 plugin 的源碼,讀起來比較方便。
2.官方對照源碼地址 android gradle plugin 源碼地址
大家可以直接 clone EasyGradle 項目,把 android-gradle-plugin-source/build.gradle 里的 implementation com.android.tools.build:gradle:3.0.1 注釋打開就可以了。
com.android.application 主要有下面幾個流程:
在前面講解自定義插件的時候說到過,要定義一個 xxx.properties 文件,裡面聲明插件的入口類,而 xxx 就是 apply plugin 時候使用的 id,這裡要知道 android gradle plugin 的入口類,看 com.android.application.properties 文件就可以,內容如下:
implementation-class=com.android.build.gradle.AppPlugin
這裡定義了入口是 AppPlugin,AppPlugin 繼承自 BasePlugin。
1.檢查插件版本
// method: BasePlugin.apply() checkPluginVersion();
2.檢查 module 是否重名
// method: BasePlugin.apply() // 方法中會遍歷所有子項目,判斷是否有重複的 id this.checkModulesForErrors();
3.初始化插件信息
// method: BasePlugin.apply() PluginInitializer.initialize(project, this.projectOptions); // 創建 Profiler 文件 ProfilerInitializer.init(project, this.projectOptions); // profiler 信息中寫入 plugin 版本 ProcessProfileWriter.getProject(project.getPath()).setAndroidPluginVersion(Version.ANDROID_GRADLE_PLUGIN_VERSION).setAndroidPlugin(this.getAnalyticsPluginType()).setPluginGeneration(PluginGeneration.FIRST);
配置項目這一階段主要做的事情:
1.檢查 gradle 版本是否匹配
// method: BasePlugin.configureProject() this.checkGradleVersion();
2.創建 AndroidBuilder和 DataBindingBuilder
3.引入 java plugin 和 jacoco plugin
this.project.getPlugins().apply(JavaBasePlugin.class); this.project.getPlugins().apply(JacocoPlugin.class);
4.設置構建完成以後的混存清理工作
實現在 BasePlugin.configureExtension()
1.創建 AppExtension,也就是 build.gradle 里用到的 android {} dsl
this.extension = this.createExtension(...);
// AppPlugin 中實現了 createExtension,創建了 android {} dsl protected BaseExtension createExtension(...) { return (BaseExtension)project.getExtensions().create("android", AppExtension.class, new Object[]{project, projectOptions, instantiator, androidBuilder, sdkHandler, buildTypeContainer, productFlavorContainer, signingConfigContainer, buildOutputs, extraModelInfo}); }
2.創建依賴管理,ndk管理,任務管理,variant管理
3.註冊新增配置的回調函數,包括 signingConfig,buildType,productFlavor
// BasePlugin.java createExtension() // map the whenObjectAdded callbacks on the containers. signingConfigContainer.whenObjectAdded(variantManager::addSigningConfig); buildTypeContainer.whenObjectAdded( buildType -> { SigningConfig signingConfig = signingConfigContainer.findByName(BuilderConstants.DEBUG); buildType.init(signingConfig); // addBuildType,會檢查命名是否合法,然後創建 BuildTypeData variantManager.addBuildType(buildType); }); // addProductFlavor 會檢查命名是否合法,然後創建 ProductFlavorData productFlavorContainer.whenObjectAdded(variantManager::addProductFlavor); // VariantManager.java // addSigningConfig 就是在 signingConfigs 里新增一個配置 public void addSigningConfig(SigningConfig signingConfig) { this.signingConfigs.put(signingConfig.getName(), signingConfig); } // VariantManager.java public void addProductFlavor(CoreProductFlavor productFlavor) { String name = productFlavor.getName(); // checkName 會檢查 checkName(name, "ProductFlavor"); if(this.buildTypes.containsKey(name)) { throw new RuntimeException("ProductFlavor names cannot collide with BuildType names"); } else { // 獲取源碼位置 DefaultAndroidSourceSet mainSourceSet = (DefaultAndroidSourceSet)this.extension.getSourceSets().maybeCreate(productFlavor.getName()); DefaultAndroidSourceSet androidTestSourceSet = null; DefaultAndroidSourceSet unitTestSourceSet = null; if(this.variantFactory.hasTestScope()) { // 獲取單測源碼位置 androidTestSourceSet = (DefaultAndroidSourceSet)this.extension.getSourceSets().maybeCreate(computeSourceSetName(productFlavor.getName(), VariantType.ANDROID_TEST)); unitTestSourceSet = (DefaultAndroidSourceSet)this.extension.getSourceSets().maybeCreate(computeSourceSetName(productFlavor.getName(), VariantType.UNIT_TEST)); }
// 創建 productFlavorData 對象 ProductFlavorData<CoreProductFlavor> productFlavorData = new ProductFlavorData(productFlavor, mainSourceSet, androidTestSourceSet, unitTestSourceSet, this.project); this.productFlavors.put(productFlavor.getName(), productFlavorData); } }
4.創建默認的 debug 簽名,創建 debug 和 release 兩個 buildType
variantFactory.createDefaultComponents( buildTypeContainer, productFlavorContainer, signingConfigContainer); // ApplicationVariantFactory.java public void createDefaultComponents(...) { signingConfigs.create("debug"); buildTypes.create("debug"); buildTypes.create("release"); }
上述準備,配置階段完成以後,就開始創建構建需要的 Task 了,是在 BasePlugin.createTasks() 里實現的,主要有兩步,創建不依賴 flavor 的 task和創建構建 task。
先看不依賴 flavor 的 task,其實現在 TaskManager.createTasksBeforeEvaluate()。
這裡主要創建了幾個 task,包括 uninstallAll,deviceCheck,connectedCheck,preBuild,extractProguardFiles,sourceSets,assembleAndroidTest,compileLint,lint,lintChecks,cleanBuildCacheresolveConfigAttr,consumeConfigAttr。
這些 task 都是不需要依賴 flavor 數據的公共 task。
在介紹下面的流程之前,先明確幾個概念,flavor,dimension,variant。
在 android gradle plugin 3.x 之後,每個 flavor 必須對應一個 dimension,可以理解為 flavor 的分組,然後不同 dimension 里的 flavor 組合成一個 variant。
舉個例子:
flavorDimensions "size", "color"
productFlavors { big { dimension "size" } small { dimension "size" } blue { dimension "color" } red { dimension "color" } }
上面配置對應生成的 variant 就是 bigBlue,bigRed,smallBlue,smallRed,在這個基礎上,再加上 buildTypes,就是 bigBlueDebug,bigRedDebug,smallBlueDebug,smallRedDebug,bigBlueRelease,bigRedRelease,smallBlueRelease,smallRedRelease。
createAndroidTasks 的調用時機和上面不一樣,是在 project.afterEvaluate 里調用的,還記得之前文章里說道的 afterEvaluate 回調么?這個時候所有模塊配置已經完成了。所以在這個階段可以獲取到對應的 flavor 以及其他配置了。
// 創建 flavor 和 dimension 的組合 List<ProductFlavorCombo<CoreProductFlavor>> flavorComboList = ProductFlavorCombo.createCombinations( flavorDimensionList, flavorDsl); // 為每個組合創建 VariantData for (ProductFlavorCombo<CoreProductFlavor> flavorCombo : flavorComboList) { //noinspection unchecked createVariantDataForProductFlavors( (List<ProductFlavor>) (List) flavorCombo.getFlavorList()); }
創建出來的 VariantData 都是 BaseVariantData 的子類,裡面保存了一些 Task,可以看一下 BaseVariantData 里的一些重要的結構,對 BaseVariantData 有個大概的了解。
public abstract class BaseVariantData implements TaskContainer { private final GradleVariantConfiguration variantConfiguration; private VariantDependencies variantDependency; private final VariantScope scope; public Task preBuildTask; public Task sourceGenTask; public Task resourceGenTask; // 資源處理 public Task assetGenTask; public CheckManifest checkManifestTask; // 檢測manifest public AndroidTask<PackageSplitRes> packageSplitResourcesTask; // 打包資源 public AndroidTask<PackageSplitAbi> packageSplitAbiTask; public RenderscriptCompile renderscriptCompileTask; public MergeResources mergeResourcesTask; // 合併資源 public ManifestProcessorTask processManifest; // 處理 manifest public MergeSourceSetFolders mergeAssetsTask; // 合併 assets public GenerateBuildConfig generateBuildConfigTask; // 生成 BuildConfig public GenerateResValues generateResValuesTask; public Sync processJavaResourcesTask; public NdkCompile ndkCompileTask; // ndk 編譯 public JavaCompile javacTask; public Task compileTask; public Task javaCompilerTask; // java 文件編譯 // ... }
VariantData 里保存了很多 task,下一步就要創建這些 task。
2.createTasksForVariantData
VariantManager.createAssembleTaskForVariantData() // 創建 assembleXXXTask TaskManager.createTasksForVariantScope() // 是一個抽象類,具體實現在 ApplicationTaskManager.createTasksForVariantScope() TaskManager.createPostCompilationTasks() // 創建 .class to dex 的 task, 創建 transformTask,我們創建的 transform 就是這個階段添加進來的,是在 addCompileTask 里調用的
// createTasksForVariantScope 是一個抽象方法,具體實現在子類中,可以看一下 ApplicationTaskManager.createTasksForVariantScope() // createTasksForVariantScope 里的實現,如果在業務中有需要查看相關 task 源碼時,可以來這裡找 void createTasksForVariantScope() { this.createCheckManifestTask(tasks, variantScope); // 檢測 manifest this.handleMicroApp(tasks, variantScope); this.createDependencyStreams(tasks, variantScope); this.createApplicationIdWriterTask(tasks, variantScope); // application id this.createMergeApkManifestsTask(tasks, variantScope); // 合併 manifest this.createGenerateResValuesTask(tasks, variantScope); this.createRenderscriptTask(tasks, variantScope); this.createMergeResourcesTask(tasks, variantScope, true); // 合併資源文件 this.createMergeAssetsTask(tasks, variantScope, (BiConsumer)null); // 合併 assets this.createBuildConfigTask(tasks, variantScope); // 生成 BuildConfig this.createApkProcessResTask(tasks, variantScope); // 處理資源 this.createProcessJavaResTask(tasks, variantScope); this.createAidlTask(tasks, variantScope); // 處理 aidl this.createShaderTask(tasks, variantScope); this.createNdkTasks(tasks, variantScope); // 處理 ndk this.createExternalNativeBuildJsonGenerators(variantScope); this.createExternalNativeBuildTasks(tasks, variantScope); this.createMergeJniLibFoldersTasks(tasks, variantScope); // 合併 jni this.createDataBindingTasksIfNecessary(tasks, variantScope); // 處理 databinding this.addCompileTask(tasks, variantScope); createStripNativeLibraryTask(tasks, variantScope); this.createSplitTasks(tasks, variantScope); this.createPackagingTask(tasks, variantScope, buildInfoWriterTask); // 打包 apk this.createLintTasks(tasks, variantScope); // lint }
// createPostCompilationTasks 實現: // 處理 Android Transform void createPostCompilationTasks() { for (int i = 0, count = customTransforms.size(); i < count; i++) { Transform transform = customTransforms.get(i); // TransformManager.addTransform 實際上是為 transform 創建了一個 Task transformManager .addTransform(tasks, variantScope, transform) .ifPresent(t -> { if (!deps.isEmpty()) { t.dependsOn(tasks, deps); } // if the task is a no-op then we make assemble task depend on it. if (transform.getScopes().isEmpty()) { variantScope.getAssembleTask().dependsOn(tasks, t); } }); } }
android gradle plugin 的主要流程基本上就結束了,主要流程圖如下所示
【Android 修鍊手冊】系列內容 每周五更新
歡迎關注下面賬號,獲取更新:
微信搜索公眾號: ZYLAB
知乎