日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

【Android 修炼手册】Gradle 篇 -- Android Gradle Plugin 主要流程分析

發布時間:2023/12/15 Android 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Android 修炼手册】Gradle 篇 -- Android Gradle Plugin 主要流程分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

預備知識

  • 理解 gradle 的基本開發
  • 了解 gradle task 和 plugin 使用及開發
  • 了解 android gradle plugin 的使用
  • 看完本文可以達到什么程度

  • 了解 android gradle plugin 的構建流程
  • 了解 android gradle plugin 的主要 task 的實現
  • 學會 hook android 構建流程,添加自己想要的功能
  • 閱讀前準備工作

  • 項目添加 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。
    AppPlugin 里沒有做太多的操作,主要是重寫了 createTaskManager 和 createExtension,剩下的大部分工作還是在 BasePlugin 里做的。
    插件準備工作中主要做的事情:

  • 檢查插件版本
  • // method: BasePlugin.apply() checkPluginVersion(); 復制代碼
  • 檢查 module 是否重名
  • // method: BasePlugin.apply() // 方法中會遍歷所有子項目,判斷是否有重復的 id this.checkModulesForErrors(); 復制代碼
  • 初始化插件信息
  • // 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); 復制代碼

    二、配置項目

    配置項目這一階段主要做的事情:

  • 檢查 gradle 版本是否匹配
  • // method: BasePlugin.configureProject() this.checkGradleVersion(); 復制代碼
  • 創建 AndroidBuilder和 DataBindingBuilder
  • 引入 java plugin 和 jacoco plugin
  • this.project.getPlugins().apply(JavaBasePlugin.class); this.project.getPlugins().apply(JacocoPlugin.class); 復制代碼
  • 設置構建完成以后的混存清理工作 添加了 BuildListener,在 buildFinished 回調里做緩存清理工作
  • 三、配置 Extension

    實現在 BasePlugin.configureExtension()
    這一階段主要做了下面幾個事情:

  • 創建 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}); } 復制代碼
  • 創建依賴管理,ndk管理,任務管理,variant管理
  • 注冊新增配置的回調函數,包括 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,會檢查命名是否合法,然后創建 BuildTypeDatavariantManager.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);} } 復制代碼
  • 創建默認的 debug 簽名,創建 debug 和 release 兩個 buildType
  • variantFactory.createDefaultComponents(buildTypeContainer, productFlavorContainer, signingConfigContainer); // ApplicationVariantFactory.java public void createDefaultComponents(...) {signingConfigs.create("debug");buildTypes.create("debug");buildTypes.create("release"); } 復制代碼

    四、創建不依賴 flavor 的 task

    上述準備,配置階段完成以后,就開始創建構建需要的 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。

    五、創建構建 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 以及其他配置了。
    在 BasePlugin.createAndroidTasks 里,是調用 VariantManager.createAndroidTasks 完成工作的。
    創建 task 的時候,會先通過 populateVariantDataList 生成 flavor 相關的數據結構,然后調用 createTasksForVariantData 創建 flavor 對應的 task。
    分別看下這兩個方法做的事情
    1.populateVariantDataList
    在方法里,會先根據 flavor 和 dimension 創建對應的組合,存放在 flavorComboList 里,之后調用 createVariantDataForProductFlavors 創建對應的 VariantData。
    其中重要的幾個方法:

    // 創建 flavor 和 dimension 的組合 List<ProductFlavorCombo<CoreProductFlavor>> flavorComboList =ProductFlavorCombo.createCombinations(flavorDimensionList,flavorDsl); // 為每個組合創建 VariantData for (ProductFlavorCombo<CoreProductFlavor> flavorCombo : flavorComboList) {//noinspection uncheckedcreateVariantDataForProductFlavors((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; // 檢測manifestpublic AndroidTask<PackageSplitRes> packageSplitResourcesTask; // 打包資源public AndroidTask<PackageSplitAbi> packageSplitAbiTask;public RenderscriptCompile renderscriptCompileTask; public MergeResources mergeResourcesTask; // 合并資源public ManifestProcessorTask processManifest; // 處理 manifestpublic MergeSourceSetFolders mergeAssetsTask; // 合并 assetspublic GenerateBuildConfig generateBuildConfigTask; // 生成 BuildConfigpublic GenerateResValues generateResValuesTask;public Sync processJavaResourcesTask;public NdkCompile ndkCompileTask; // ndk 編譯public JavaCompile javacTask; public Task compileTask;public Task javaCompilerTask; // java 文件編譯// ... } 復制代碼

    VariantData 里保存了很多 task,下一步就要創建這些 task。

    2.createTasksForVariantData
    創建完 variant 數據,就要給 每個 variantData 創建對應的 task,對應的 task 有 assembleXXXTask,prebuildXXX,generateXXXSource,generateXXXResources,generateXXXAssets,processXXXManifest 等等,重點關注幾個方法:

    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); // 檢測 manifestthis.handleMicroApp(tasks, variantScope);this.createDependencyStreams(tasks, variantScope);this.createApplicationIdWriterTask(tasks, variantScope); // application id this.createMergeApkManifestsTask(tasks, variantScope); // 合并 manifestthis.createGenerateResValuesTask(tasks, variantScope);this.createRenderscriptTask(tasks, variantScope);this.createMergeResourcesTask(tasks, variantScope, true); // 合并資源文件this.createMergeAssetsTask(tasks, variantScope, (BiConsumer)null); // 合并 assetsthis.createBuildConfigTask(tasks, variantScope); // 生成 BuildConfigthis.createApkProcessResTask(tasks, variantScope); // 處理資源this.createProcessJavaResTask(tasks, variantScope);this.createAidlTask(tasks, variantScope); // 處理 aidlthis.createShaderTask(tasks, variantScope);this.createNdkTasks(tasks, variantScope); // 處理 ndkthis.createExternalNativeBuildJsonGenerators(variantScope);this.createExternalNativeBuildTasks(tasks, variantScope);this.createMergeJniLibFoldersTasks(tasks, variantScope); // 合并 jnithis.createDataBindingTasksIfNecessary(tasks, variantScope); // 處理 databindingthis.addCompileTask(tasks, variantScope); createStripNativeLibraryTask(tasks, variantScope);this.createSplitTasks(tasks, variantScope);this.createPackagingTask(tasks, variantScope, buildInfoWriterTask); // 打包 apkthis.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 創建了一個 TasktransformManager.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 的主要流程基本上就結束了,主要流程圖如下所示

    這里總結幾個要點:

  • com.android.application 入口類是 AppPlugin,但大部分工作都是在 BasePlugin 里完成的
  • build.gradle 里見到的 android {} dsl 是在 BasePlugin.configureExtension() 里聲明的
  • 主要的 task 是在 BasePlugin.createAndroidTasks() 里生成的
  • 主要 task 的實現可以在 TaskManager 中找到
  • transform 會轉化成 TransformTask
  • 【Android 修煉手冊】系列內容 每周五更新
    歡迎關注下面賬號,獲取更新:
    微信搜索公眾號: ZYLAB
    Github
    掘金

    總結

    以上是生活随笔為你收集整理的【Android 修炼手册】Gradle 篇 -- Android Gradle Plugin 主要流程分析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。