Gradle
是每个 Android
同学都逃不开的一个话题。
你是否看到别人的 Gradle
文件干净又卫生?而自己的又是一团乱麻🏷
不用怕,本篇将结合我的开发日常,将一些常用的操作分享出来,希望可以帮到像我一样不怎么会[玩]Gradle
的同学,相信会对大家有所帮助。
模板代码提取
这是最基础的操作了,对于一个普通 model.gradle
,默认的配置如下:
如果我们每个 model
都这样写,那岂不是很麻烦,那么让我们提取通用代码:
优化步骤
新建一个 gradle
文件,命名为 xxx.gradle
,复制上述 model
里的配置,放到你的项目中,可以自定义修改一些通用内容,在其他model
中依赖即可,如下所示:
这是一个播放器model
// 这就是刚才新建的默认gradle文件, // 注意:如果你的default.gradle是在项目目录下,请使用../,如果仅在app下,请使用./ apply from: "../default.gradle" import xxx.* android { // 用于隔离不同model的资源文件 resourcePrefix "lc_play_" } dependencies { compileOnly project(path: ':common') api xxx }
上述的 android{} , dependencies{}
其内部的内容都会在 default.gradle
的基础上叠加,对于唯一的键值对,会进行替换。
定义统一的config配置
在项目中,你是如何去写你的版本号等其他默认配置呢?
对于一个新项目,其默认的配置如下所示,每次新创建 model
,也需要定义其默认参数,如果每次都直接在这里去改动,那么如果版本变化,意味着我们需要修改多次,这并不是我们想看到的效果。
优化步骤
新建 config.gradle ,内容如下:
// 一些配置文件的保存 // 使用git的commit记录当做versionCode static def gitVersionCode() { def cmd = 'git rev-list HEAD --count' return cmd.execute().text.trim().toInteger() } static def releaseBuildTime() { return new Date().format("yyyy.MM.dd", TimeZone.getTimeZone("UTC")) } ext { android = [compileSdkVersion: 30, applicationId : "com.xxx.xxx", minSdkVersion : 21, targetSdkVersion : 30, buildToolsVersion: "30.0.2", buildTime : releaseBuildTime(), versionCode : gitVersionCode(), versionName : "1.x.x"] }
使用时:
android { def android = rootProject.ext.android defaultConfig { multiDexEnabled true minSdk android.minSdkVersion compileSdk android.compileSdkVersion targetSdk android.targetSdkVersion versionCode android.versionCode versionName android.versionName } }
配置你的build
配置不同build类型
在开发中,我们一般会有多个环境,比如 开发环境 ,测试环境,线上环境:
buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } dev{ // initWith代表的是允许从其他build类型进行复制操作,然后配置我们想更改的设置 // 这里代表的是从release复制build配置 initWith release // 清单占位符 manifestPlaceholders = [hostName:"com.petterp.testgradle.dev"] // 会在你原包名后面新增.test applicationIdSuffix ".dev" } }
如上所述,dev
是我们新增的 build类型 ,当新增之后,我们就可以在命令行使用如下匹配的指令,或者点击As 最右侧,gradle图标,选择app(根据自己build的配置位置而定,一般默认是app-model),选择other,即可看到多了如下几个指令:
当然你也可以选择如下命令行执行,以便在 Jenkins 或者 CI 下 build
时执行:
gradlew buildDev gradlew assembleDev
注意,mac下是gradlew开头,windows下可能是./gradlew
配置变体
对于开发中,我们一般都有多渠道的需求,一般而言,如果仅仅是多渠道我们可以选择使用第三方 walle 去做,如果我们可能还有更精细的设置,比如针对这个 build类型,我们很可能对应了不同的默认配置等,比如配置不同的 applicationId
,资源。
如下所示:
// 变体风味名,如果只设置一个,则所有变体会自动使用,如果存在两个及以上,需要在变体中指定,并且变体需要与分组匹配。 // 风味名,类似于风格,分组的意思。 flavorDimensions "channel" // flavorDimensions ("channel","api") productFlavors { demo1 { // 每一个变体都必须存在一个风味,默认使用flavorDimensions(仅限其为单个时)的值,否则如果没提供,则会报错。 dimension "channel" // appid后缀,会覆盖了我们build类型中的applicationIdSuffix applicationIdSuffix ".demo" // 版本后缀 versionNameSuffix "-demo" } demo2 { dimension "channel" applicationIdSuffix ".demo2" versionNameSuffix "-demo2" } }
然后查看我们的 build Variants:
Gradle 会根据我们的 变体
和 build类型
自动创建多个build变种,按照 变体名-build类型名
方式命名。
在配置变体时,我们也可以替换在 build类型
中设置的所有默认值,具体原因是,在添加 build类型
时,默认的 defaultConfig
配置其实是属于 ProductFlavors
类,所以我们也可以在任意变体中替换所有默认值。
组合多个变体
在某些场景下,我们可能想将多个产品的变体组合在一起,比如我们想增加一个 api30 的变体,并且针对这个变体,我们想让demo1和demo2与分别也能与其组合在一起 ,即也就是当channel是demo1时api30下对应的包。
理解起来有些拗口,示例如下所示,我们更改上面的配置:
flavorDimensions("channel", "api") productFlavors { demo1 { dimension "channel" applicationIdSuffix ".demo" versionNameSuffix "-demo" } demo2 { dimension "channel" applicationIdSuffix ".demo2" versionNameSuffix "-demo2" } minApi23 { dimension "api" minSdk 23 applicationIdSuffix ".minapi23" versionNameSuffix "-minapi23" } }
最终如下所示,左侧是 gralde
生成的 build变种 ,右侧对应其中 demo1MinApi23Debug
打包后的产物具体信息:
所以我们可以总结为:
最终我们在打包时,我们的包名和版本名会根据多个变体混合生成,具体如上图所示,然后分别使用了两者都具有的配置,当配置出现重复时,优先以开头的变体配置作为基准。
比如如果我们给demo1变体也配置了最低sdk版本是21,那么最终打出来的包minSdk也会是21,而不是minApi23中的minSdk配置,这点需要注意。
解疑
那么 变体
和 build类型
两者到底应该怎么选?似乎两者好像很是相似?
其实不难理解,如下所示:
比如你新增了一个变体 firDev
,那么默认情况下就会有如下的 build命令 生成
firDevDebug firDevRelase firDevXXX(xxx是你自定义的build类型)
需要注意的是 debug
和 relase
是默认就会存在的,我们可以选择覆盖,否则就算移除,其也会选择默认设置存在
即也就是最终 gradle 会帮我们每个变体都生成相应的 build类型 对应的命令,变体就相当于不同的渠道,而 build类型 就相当于针对这个渠道,存在着多种环境,比如 debug,relase,你自定义的更多build类型。
- 所以如果你的场景仅仅是想对应几个不同环境,那么直接配置 build类型 即可;
- 如果你可能希望区分不同的包下的依赖项或者资源配置,那么配置变体即可。