0
点赞
收藏
分享

微信扫一扫

Android 基于Gradle 7.4.2,自定义插件示例

文风起武 2022-04-28 阅读 75

文章目录

起源

前几天,找到了之前从官方公众号中,收藏的文章,来简单学习一波Gradle与AGP
就是这一篇:Gradle 与 AGP 构建 API: 进一步完善您的插件!,文章内部会发现,这是一个小系列,共有3篇文章。
文章对应的官方代码示例 gradle-recipes

示例中用的是 gradle 7.1的alpha版本,而我这边由于工作需要,本地升级过其它项目到7.2了。
结果呢,文章中的示例代码,大部分在我这运行不起来。真是怀疑人生啊!!!
后来,由于不能运行 ProcessBuilder,升级了gradle到 7.4.2,然而,发现还是不能在task中以ProcessBuilder 运行命令。


环境配置

工程下的 build.gradle

// all buildscript {} blocks must appear before any plugins {} blocks in the script
buildscript { // gradle 构建脚本 自身,所需的
repositories {
google()
mavenCentral()
}

dependencies {
// https://mvnrepository.com/artifact/com.android.tools.build/gradle?repo=google
classpath("com.android.tools.build:gradle:7.2.0-rc01")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.20")
}
}

// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '7.2.0-rc01' apply false
id 'com.android.library' version '7.2.0-rc01' apply false
id 'org.jetbrains.kotlin.android' version '1.6.20' apply false
}

//apply plugin: CustomPlugin

task clean(type: Delete) {
delete rootProject.buildDir
}

为了编译插件,在工程下创建 buildSrc目录。
为了使用kotlin,将build.gradle 增加.kts后缀。

buildSrc/build.gradle.kts

plugins {
`kotlin-dsl` // 使用这个后 buildSrc/src/main/kotlin 才成为源码目录
}

repositories { // project 所需的 repos
google()
mavenCentral()
}

dependencies { // project 所需的 depends
// 这个必须依赖,不然一些 gradle 中的api 无法使用
implementation("com.android.tools.build:gradle-api:7.1.3")
implementation(kotlin("stdlib", version = "1.6.20"))
// val ga = gradleApi() // 暂没看出来有什么作用
// print: " gradle 2api: null unspecified null "
// println("gradle api: ${ga.group} ${ga.name} ${ga.version}")
}

插件中增加变体variant(示例)

什么是变体,其实就是 android { } 中配置的 buildType { }。
也是,如下图的东西
在这里插入图片描述

代码不复杂,直接贴了

import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.register
import  com.android.build.api.variant.ApplicationAndroidComponentsExtension

class CustomPlugin : Plugin<Project> {
	// 在哪里 apply plugin,那里所属的项目或模块就是这个 project 对象
    override fun apply(project: Project) {
    	addVariant(project, "staging")
    }
	
	// 添加构建变体
    private fun addVariant(project: Project, variantName: String) {
        val extension = project.extensions.getByName(
            "androidComponents"
        ) as ApplicationAndroidComponentsExtension // android应用组件扩展

        // finalizeDsl, 在 DSL 对象应用于 Variant 创建前对它们进行修改
        // 在阶段结束时,AGP 将会锁定 DSL 对象,这样它们就无法再被更改
        extension.finalizeDsl { ext->
            println("finalizeDsl")
            ext.buildTypes.create(variantName).let { buildType ->
                buildType.initWith(ext.buildTypes.getByName("debug"))
                buildType.manifestPlaceholders["hostName"] = "example.com"
                buildType.applicationIdSuffix = ".debug$variantName"
                buildType.isDebuggable = true
                buildType.isShrinkResources = false // 是否压缩资源
                buildType.isMinifyEnabled = false // 是否混淆
            }
        }
		// 在每个变体锁定之前
        extension.beforeVariants { variantBuilder ->
            println("beforeVariants ${variantBuilder.name}")
            if (variantBuilder.name == variantName) {
                variantBuilder.enableUnitTest = false
                variantBuilder.minSdk = 23
            }
        }
    }
}

在android application 模块的 build.gradle.kts 中应用 插件:
apply<CustomPlugin>()
然后在命令行执行命令
./gradlew :app:compileStagingSources
输出:

finalizeDsl
beforeVariants debug
beforeVariants release
beforeVariants staging

插件中修改manifest的version code值(示例)

这个示例,用到了 task,还是一个task套另一个task。还有文件输出与输入,manifest读取与合并等。
本来官方的示例,是以读取 git commint-id的 short 的 sha-1值 ,来改写 androidmanifest 中的 version code值。结果,并不能运行那段命令代码,搜索了一堆资料,也没搞定,放弃了。看了官方的示例,把那段也注释掉了,真有意思,哈哈。 所以也和他们一样,简单向文件内写入个数字。

GitVersionTask

package gitversion

import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import java.io.BufferedReader
import java.io.InputStreamReader

abstract class GitVersionTask : DefaultTask() {

    // RegularFileProperty, 表示某个可配置的常规文件位置,其值是可变的。
    @get:OutputFile
    abstract val gitVersionOutputFile: RegularFileProperty

    @TaskAction
    fun taskAction() {
		// 向文件内写入字符串
        gitVersionOutputFile.get().asFile.writeText("3234")
	}
}

ManifestTransformerTask

package gitversion

import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction

abstract class ManifestTransformerTask: DefaultTask() {

   @get:InputFile
   abstract val gitInfoFile: RegularFileProperty

   @get:InputFile
   abstract val mergedManifest: RegularFileProperty

   @get:OutputFile
   abstract val updatedManifest: RegularFileProperty

   @TaskAction
   fun taskAction() {
      val gitVersion = gitInfoFile.get().asFile.readText()
      var manifest = mergedManifest.asFile.get().readText()
      manifest = manifest.replace(
         "android:versionCode=\"1\"",
         "android:versionCode=\"${gitVersion}\""
      )

      // 先 get或先 asFile,都可以的,最终都是 File 对象
      // updatedManifest.get().asFile.writeText(manifest)
      updatedManifest.asFile.get().writeText(manifest)
   }
}

GitVersionPlugin

package gitversion

import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.register
import java.io.File
import com.android.build.api.variant.AndroidComponentsExtension
import org.gradle.api.tasks.TaskProvider
import org.gradle.kotlin.dsl.getByType
import com.android.build.api.artifact.SingleArtifact

class GitVersionPlugin: Plugin<Project> {

    override fun apply(project: Project) {
        // ./gradlew :app:gitVersionProvider
        val gitVersionProvider = project.tasks.register<GitVersionTask>("gitVersionProvider") {
            // 对输出文件属性赋值一个文件对象 app/build/intermediates/gitVersionProvider/output
            gitVersionOutputFile.set(File(project.buildDir, "intermediates/gitVersionProvider/output"))
            outputs.upToDateWhen { false } // 将 upToDateWhen 设置为 false,这样此 Task 前一次执行的输出就不会被复用
        }

        val androidComponents = project.extensions.getByType(
            AndroidComponentsExtension::class
        )
        androidComponents.onVariants { variant ->
            // staging/debug/release ManifestUpdater,   $ ./gradlew :app:stagingManifestUpdater
            // 输出文件位置:app/build/intermediates/merged_manifest/staging/[build variant]ManifestUpdater/AndroidManifest.xml
            val manifestUpdater: TaskProvider<ManifestTransformerTask> = project.tasks.register<ManifestTransformerTask>(variant.name + "ManifestUpdater") {
                // 设置输入(对 ManifestTransformerTask来说,是输入),输入的是 GitVersionTask 的输出 gitVersionOutputFile
                gitInfoFile.set(gitVersionProvider.get().gitVersionOutputFile)
                // gitInfoFile.set(gitVersionProvider.flatMap {
                //     it.gitVersionOutputFile
                // })
            }
            variant.artifacts.use(manifestUpdater)
                .wiredWithFiles(ManifestTransformerTask::mergedManifest, ManifestTransformerTask::updatedManifest)
                .toTransform(SingleArtifact.MERGED_MANIFEST)

        }
}

在android application 模块的 build.gradle.kts 中应用 插件:
apply<gitversion.GitVersionPlugin>()
然后在命令行执行命令
./gradlew :app:stagingManifestUpdater
最终生成:
app/build/intermediates/merged_manifest/staging/stagingManifestUpdater/AndroidManifest.xml
在这里插入图片描述


示例源码

以上内容,对应于今天以前的提交记录。

传送门

举报

相关推荐

0 条评论