Android Flavor配置

594 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第31天,点击查看活动详情

Flavor配置

在 android gradle plugin V3.x 之后,每个 flavor 必须对应一个 dimension,可以理解为 flavor 的分组,然后不同 dimension 里的 flavor 会组合成一个 variant。示例代码如下所示:

flavorDimensions "size""color"

productFlavors {
    BeiYang {
        dimension "size"
    }
    small {
        dimension "size"
    }
    blue {
        dimension "color"
    }
    red {
        dimension "color"
    }
}

在 Android 对 Gradle 插件的扩展支持之中,其中最常用的便是 利用变体(Variants)来对构建过程中的各个默认的 task 进行 hook。关于 Variants 共有 三种类型,如下所示:

  • 1)、applicationVariants:只适用于 app plugin。
  • 2)、libraryVariants:只适用于 library plugin。
  • 3)、testVariants:在 app plugin 与 libarary plugin 中都适用。

ApplicationVariants

productFlavors {
    douyin {}
    weixin {}
    google {}
}

在配置阶段结束后获取所有变体的名称

this.afterEvaluate {
    this.android.applicationVariants.all { variant ->
        def name = variant.name
        def baseName = variant.baseName
        println "name: $name, baseName: $baseName"
    }
}
输出:
> Configure project :app
name: douyinDebug, baseName: douyin-debug
name: douyinRelease, baseName: douyin-release
name: weixinDebug, baseName: weixin-debug
name: weixinRelease, baseName: weixin-release
name: googleDebug, baseName: google-debug
name: googleRelease, baseName: google-release
可以看到,name 与 baseName 的区别:baiduDebug 与 baidu-debug 。

再配置阶段结束后更改输出apk的名字

this.afterEvaluate {
    this.android.applicationVariants.all { variant ->
        variant.outputs.each {
            // 由于我们当前的变体是 application 类型的,所以
            // 这个 output 就是我们 APK 文件的输出路径,我们
            // 可以通过重命名这个文件来修改我们最终输出的 APK 文件
            outputFileName = "app-${variant.baseName}-${variant.versionName}.apk"
            println outputFileName
        }
    }
}
输出
> Configure project :app
app-debug-1.0.apk
app-release-1.0.apk

通过遍历变体的outputs这个就是所有的apk输出路径,更改outputFileName属性即可更改输出的apk名称

对applicationVariants的Task进行Hook

我们可以在 android.applicationVariants.all 的闭包中通过 variant.task 来获取相应的 Task。

this.afterEvaluate {
    this.android.applicationVariants.all { variant ->
        def task = variant.checkManifest
        println task.name
    }
}

输出:
checkDebugManifest
checkReleaseManifest

可以获取到变体中的task的话,我们就可以根据不同Task的类型做特殊处理

Transform

Google 官方在 Android Gradle V1.5.0 版本以后提供了 Transfrom API, 允许第三方 Plugin 在打包成 .dex 文件之前的编译过程中操作 .class 文件,我们需要做的就是实现 Transform 来对 .class 文件遍历以拿到所有方法,修改完成后再对原文件进行替换即可。

总的来说,Gradle Transform 的功能就是把输入的 .class 文件转换为目标字节码文件。 下面,我们来了解一下 Transform 的两个基础概念。

TransformInput

TransformInput 可认为是所有输入文件的一个抽象,它主要包括两个部分,如下所示:

DirectoryInput 集合:表示以源码方式参与项目编译的所有目录结构与其目录下的源码文件。

JarInput 集合:表示以 jar 包方式参与项目编译的所有本地 jar 包和远程 jar 包。需要注意的是,这个 jar 所指也包括 aar。

TransformOutputProvider

表示 Transform 的输出,利用它我们可以获取输出路径等信息。

实现Transform

在BuldSrc项目中配置Android DSL仓库依赖

由于 buildSrc 的执行时机要早于任何一个 project,因此需要⾃⼰添加仓库

// 由于 buildSrc 的执行时机要早于任何一个 project,因此需要⾃⼰添加仓库 
repositories {
    google()
    jcenter() 
}

dependencies {
    // Android DSL
    implementation 'com.android.tools.build:gradle:3.6.2'
}

继承 com.android.build.api.transform.Transform ,创建⼀个 Transform 的子类

其创建步骤可以细分为五步,如下所示:

  • 重写 getName 方法:返回对应的 Task 名称。
  • 重写 getInputTypes 方法:确定对那些类型的结果进行转换。
  • 重写 getScopes 方法:指定插件的适用范围。
  • 重写 isIncremental 方法:表示是否支持增量更新。
  • 重写 transform 方法:进行具体的转换过程。