Android:Gradle 通用配置

完整配置的Guthub地址:https://github.com/WangFion/mvp-mode

一、什么是 Gradle


  关于 Gradle 是什么,这里我就不做过多的赘述了,打开度娘一搜一大片,感兴趣的童鞋可以自行学习哈!这里我就简单描述一下:
  Gradle 是一个基于 Apache Ant 和 Apache Maven 概念的项目自动化构建工具。它使用一种基于 Groovy 的特定领域语言来声明项目设置,而不是传统的 XML。Gradle 就是工程的管理,帮我们做了依赖、打包、部署、发布、各种渠道的差异管理等工作。
  这里你只需要己住一点:Gradle 是一个自动化构建工具,这就ok了。


二、AS 中的 Gradle 版本


  在 Android Studio 中使用 Gradle 有三个版本需要注意:AS 版本、Gradle 插件版本、Gradle 版本。

1、AS版本

AS-Version.png

2、Gradle 插件版本(项目根目录的 build.gradle

classpath 'com.android.tools.build:gradle:3.6.3'

3、Gradle 版本(项目根目录的 /gradle/wrapper/gradle-wrapper.properties

#Sat May 09 20:18:45 CST 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip

1、其中 AS 的版本和 Gradle 插件的版本是有对应关系的,Gradle 版本根据项目而定,建议都保持最新版本。
2、有新版本,如果更新之后编译不过并且很难解决,亦可保持原编译通过版本不变。
3、个人建议有新版本就及时更新,不要累积很多版本后一次更新;否则到必须更新的时候再去更新,相信我你会痛苦万分的。


三、Project 的 Gradle 通用配置


  Project 的 Gradle 配置的是项目统一化、公用化的一些信息,目的是为了保证公共的信息在每个 Module 中都是一致的,而每个 Module 只需要去配置自己的一些差异化的信息。
  Project 的 Gradle 的配置文件是根目录下面的 build.gradle,这里面主要配置远程仓库、插件、项目版本信息、公共 lib 等。

1、远程仓库配置

repositories {
    // wf-update: 2020/5/9 16:57 添加aliyun镜像,优化jcenter和google访问
    maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
    maven { url 'https://maven.aliyun.com/repository/jcenter' }
    maven { url 'https://maven.aliyun.com/repository/google' }
    google()
    jcenter()
}

往往在我们项目开发的过程中都会集成很多 Google 和第三方的开源库,而受国内环境的影响使用 google() 和 jcenter() 下载这些库往往不尽人意,所以这里推荐配置国内的镜像地址(当然不止我上面列举的这些),会有意想不到的效果哦。注意这里需要同时配置 buildscriptallprojects 方法块。

2、插件配置

dependencies {
    classpath 'com.android.tools.build:gradle:3.6.3'
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

    // NOTE: Do not place your application dependencies here; they belong
    // in the individual module build.gradle files
}

注意这里的 dependencies 配置的是项目编译所用到的插件,一定要区别于 Module 里面的 dependencies ,注意阅读 NOTE 的英文说明。上例中我们配置了一个 Gradle 插件和 Kotlin 插件。

3、项目版本信息

/**
 * 应用版本相关配置信息
 */
ext {
    applicationId      = "com.wf.mvp.mode"
    apkName            = "MvpMode"
    versionCode        = 1
    versionName        = "v1.0"
    compileSdkVersion  = 29
    buildToolsVersion  = "29.0.2"
    minSdkVersion      = 19
    targetSdkVersion   = 29
}

这里配置的是我们项目的包名、版本号、sdk 版本、编译版本等信息,当然了这里我们只是定义,具体的使用是在每个 Module 里面通过 rootProject.applicationId 的形式来调用,项目的每个 Module 都通过这种形式来配置版本信息后,后续版本调整我们就只需要修改这里就 ok 了。

4、公共 lib 配置

/**
 * Module通用lib
 */
ext {
    lib_kotlin            = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    lib_appcompat         = 'androidx.appcompat:appcompat:1.1.0'
    lib_core_ktx          = 'androidx.core:core-ktx:1.2.0'
    lib_constraintlayout  = 'androidx.constraintlayout:constraintlayout:1.1.3'
    lib_junit             = 'junit:junit:4.13'
    lib_ext_junit         = 'androidx.test.ext:junit:1.1.1'
    lib_espresso_core     = 'androidx.test.espresso:espresso-core:3.2.0'
}

同上面的版本信息一样,公用的 lib 库我们也可以定义在这里,子 Module 亦是通过 rootProject.lib_appcompat 的形式来调用,当然了和上面的版本信息写在一个 ext 方法块里面也可以,为了区分我们这里是分开写的。


四、Module 的 Gradle 通用配置


  这里 Module 的 Gradle 主要是用来配置各个 Module 的差异化信息,公共的信息均调用 Project 的 Gradle 里面定义好的。
  Module 的 Gradle 的配置文件是相应的 Module 目录下面的 build.gradle,这里面主要配置插件引用、版本信息、签名信息、编译信息、渠道信息、APK格式化输出、第三方框架及 lib 引用 等。

1、插件引用

// path -> app/build.gradle
apply plugin: 'com.android.application'
// apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

  第一行配置此 Module 为 Application 还是 Library,为 Application 时可以单独运行。这里在组件化开发中尤为重要,可以通过参数来配置此 Module 为 Application 还是 Library。
  后面两行为配置的 Kotlin 支持插件,当然了这里还可以配置一些其他需要用到的插件。

2、版本信息

// path -> app/build.gradle
// --------------- wf-update: 2020/5/9 17:53 版本配置信息 ---------------
compileSdkVersion rootProject.compileSdkVersion
buildToolsVersion rootProject.buildToolsVersion

defaultConfig {
    applicationId rootProject.applicationId
    minSdkVersion rootProject.minSdkVersion
    targetSdkVersion rootProject.targetSdkVersion
    versionCode rootProject.versionCode
    versionName rootProject.versionName

    buildConfigField("String", "DEFAULT_CONFIG", "\"default\"")

    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

  这里配置的是应用版本相关的信息,此信息均定义在 Project 的 Gradle 里面,故这里均引用的 Project 的 Gradle 里面定义的信息。所有的 Module 版本信息都应参照这里配置来保证整个工程的版本一致。

buildConfigField 定义的字段可以在代码中通过 BuildConfig.DEFAULT_CONFIG 的形式来调用,这在后面讲到的版本和渠道里面会非常有用。注意这里定义的字符串需要加上双引号

3、签名信息

// path -> app/build.gradle
// --------------- wf-update: 2020/5/9 17:55 签名配置信息 ---------------
signingConfigs {
    debug {

    }
    release {
        keyAlias 'mvp'
        keyPassword 'mvp123'
        storeFile file('../sign/mvp.jks')
        storePassword 'mvp123'
    }
}

  签名信息配置没什么特别的,签名文件可以使用 AS 或者其他签名文件生成工具均可。具体的步骤这里不再赘述,可以自行百度。

4、编译信息

// path -> app/build.gradle
// --------------- wf-update: 2020/5/20 19:04 版本编译信息 ---------------
buildTypes {
    debug {
        buildConfigField("String", "BUILD_TYPES", "\"build_debug\"")
    }
    release {
        buildConfigField("String", "BUILD_TYPES", "\"build_release\"")
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        signingConfig signingConfigs.release
    }
}

  编译信息配置用来配置我们编译的版本是 debug 还是 release,不同的版本我们可以配置不同的信息以及变量等。这里我们在 release 版本中配置了上面定义的签名信息,而 dubug 没有。当我们使用 assemble 命令编译时会在 app/build/outputs/apk 目录下同时输出 debug 和 release 版本的apk,而单独使用 assembleDebug 或者 assembleRelease 只会输出对应的一个版本的apk。

5、渠道信息

// path -> app/src/main/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.wf.mvp.mode"
    android:sharedUserId="${SHARED_USER_ID}">

    <application ......>
        ......
        <meta-data
            android:name="CHANNEL_INFO"
            android:value="${CHANNEL_VALUE}" />
    </application>

</manifest>
// path -> app/build.gradle
// --------------- wf-update: 2020/5/19 20:36 渠道配置信息 ---------------
flavorDimensions "company", "channel"
productFlavors {
    huawei {
        dimension "company"
        buildConfigField("String", "FLAVOR_COMPANY", "\"huawei\"")
        manifestPlaceholders = [
                SHARED_USER_ID: "android.uid.huawei",
                CHANNEL_VALUE : "huawei"
        ]
    }
    xiaomi {
        dimension "company"
        buildConfigField("String", "FLAVOR_COMPANY", "\"xiaomi\"")
        manifestPlaceholders = [
                SHARED_USER_ID: "android.uid.xiaomi",
                CHANNEL_VALUE : "xiaomi"
        ]
    }

    phone {
        dimension "channel"
        buildConfigField("String", "FLAVOR_COMPANY", "\"phone\"")
        buildConfigField("String", "FLAVOR_CHANNEL", "\"phone\"")
        manifestPlaceholders = [
                SHARED_USER_ID: "android.uid.phone",
                CHANNEL_VALUE : "phone"
        ]
    }
    tv {
        dimension "channel"
        buildConfigField("String", "FLAVOR_COMPANY", "\"tv\"")
        buildConfigField("String", "FLAVOR_CHANNEL", "\"tv\"")
        manifestPlaceholders = [
                SHARED_USER_ID: "android.uid.tv",
                CHANNEL_VALUE : "tv"
        ]
    }
}

  渠道配置是针对不同的渠道而进行的差异化配置。这里有以下几点需要说明:

  • 多渠道维度(flavorDimensions): AS 3.0之后出现的,至少需要定义一个维度。举个栗子:A 厂商生产了 C、D 两个产品,B 厂商也生产了 C、D 两个产品,这里就需要用到二维渠道了,就会有 AC、AD、BC、BD 四个产品。
  • 渠道维度顺序:渠道维度的定义是有先后顺序的,如果渠道里面有相同的配置信息,先定义的维度会覆盖后定义的维度,如上例中的 FLAVOR_COMPANY、SHARED_USER_ID 和 CHANNEL_VALUE 的值始终都会是 company 维度下的 huawei 或者 xiaomi,不可能为 channel 维度下的 phone 或者 tv。可以去 app/build/generated/source/buildConfig 下的 BuildConfig.java 文件中验证。

6、APK格式化输出

// path -> app/build.gradle
// --------------- wf-update: 2020/5/9 17:58 APK格式化输出配置 ---------------
applicationVariants.all { variant ->
    variant.outputs.all {
        def fileName
        def formattedDate = new Date().format("yyyy-MM-dd-HHmmss")
        if (variant.buildType.name == 'release') {
            fileName = "${rootProject.apkName}_${variant.mergedFlavor.versionName}_${formattedDate}_release.apk"
        } else {
            fileName = "${rootProject.apkName}_${variant.mergedFlavor.versionName}_${formattedDate}_debug.apk"
        }
        outputFileName = fileName
    }
}

  这里也没有什么好讲的,自行根据项目来定义 apk 的输出名称,默认的输出路径是 app/build/outputs/apk,也可以修改此输出路径,但是修改输出路径后,当我们在使用 AS run 来调试应用的时候可能会报找不到 xxx.apk 的错误,所以建议不要修改。

7、第三方框架及 lib 引用

// path -> app/build.gradle
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation rootProject.lib_kotlin
    implementation rootProject.lib_appcompat
    implementation rootProject.lib_core_ktx
    implementation rootProject.lib_constraintlayout
    testImplementation rootProject.lib_junit
    androidTestImplementation rootProject.lib_ext_junit
    androidTestImplementation rootProject.lib_espresso_core

    //引用其他 Module
    implementation project(path: ':mvp-kotlin')
    implementation project(path: ':mvp-java')

    //内存泄漏
    debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.3'
}

  这里主要用来引用需要的外部库文件和 Library Module,通用的库我们还是通过 rootProject.lib_appcompat 的形式来引用我们在 Project 里面定义好的,保证通用库版本统一。注意区别这里的 dependencies 和我们上面讲到的 Project 的 build.gradle 里面的 dependencies。


总结


  到这里,我们基础的、也是大多数项目必须的通用配置就讲完了,任何一个新项目把这套配置拿过去基本上都能满足需求。当然了 Gradle 用法远不止这些,像是源文件路径配置、ndk 配置、编译检测等等,感兴趣的童鞋可以自己去研究。以上就是本篇文章的全部内容,如有错误的地方或者更好的建议欢迎在下方留言讨论,谢谢!

完整配置的Guthub地址:https://github.com/WangFion/mvp-mode

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,047评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,807评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,501评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,839评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,951评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,117评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,188评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,929评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,372评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,679评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,837评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,536评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,168评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,886评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,129评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,665评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,739评论 2 351