Android 基于Gradle 7.2+,自定义插件示例(实测7.4.2也可以运行)

环境配置

工程下的 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 { }。
也是,如下图的东西
在这里插入图片描述

示例中,会增加一个 staging的变体。通过插件来完成。

代码不复杂,直接贴了

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

创建变体还有一些简单的方式,我的示例中,试了 “构建变体,方式1、2、3” ,就定义在 app/build.gradle.kts 中。


插件中修改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)
   }
}

@get:InputFile 用于读取数据
@get:OutputFile 用于写入数据

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)

        }
}

/*
* GitVersionPlugin, 注册 []ManifestUpdater 任务,其依赖了 ManifestTransformerTask。
*
* 当执行 ./gradlew :app:stagingManifestUpdater;
* 发现 其依赖了 gitVersionProvider 的 GitVersionTask;
* GitVersionTask 输出文本,并创建文件到 app/build/intermediates/gitVersionProvider/output;
* manifestUpdater 的 ManifestTransformerTask, 读取 gitVersion 文本;
* 在 manifest 文件中替换文本,得到了 app/build/intermediates/merged_manifest/staging/[build variant]ManifestUpdater/AndroidManifest.xml
*/
有意思的是,AS编译器内好几个地方报红,但运行是正常的。

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

试了,对 app项目打了个包,发现 version code 已等于 3234了


示例源码

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

传送门

补更: 神奇了,发现 加一段代码后, ProcessBuilder 又能运行了。
对应 git commint:processBuilder 重定错误输出流后,可以执行命令了

// 代码运行这个命令,会提示 is not a git command 。 而单独放到命令行运行,是可以的。真晕
// val processBuilder = ProcessBuilder(“git”, “rev-parse --short HEAD”)
// 这个可以正常运行
val processBuilder = ProcessBuilder(“git”, “–version”)
// 如果此属性为true,则由该对象的start()方法随后启动的子进程生成的任何错误输出将与标准输出合并,
// 以便可以使用Process.getInputStream()方法读取它们。初始值为false
processBuilder.redirectErrorStream(true)
val process = processBuilder.start()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值