Gradle for Android 简要记录

一.基础概念

  1. Gradle 有约定优于配置的原则,即为设置和属性提供默认值。

  2. Gradle 是基于 Groovy 领域专用语言 DSL.

  3. 在 Gradle 中,最重要的两个概念是项目和任务。每一次构建都包括至少一个项目,每一个项目又包括多个任务。每个 build.gradle 文件都代表着一个项目,任务定义在构建脚步里。

  4. 源集 source set
    一 个源集是一组源文件,它们会一起执行和编译。
    在 Android 中,main 就是一个源集。
    这里写图片描述

二. 常用命令

./gradlew assemble 生成 releas 和 debug 版本, 如果是配置了多渠道,则每个渠道都会生成 Release 和 Debug 版本

./gradlew assembleRelease 则会为每个渠道生成 Release 包, ./gradlew assembleDebug 类似

// 可以指定渠道版本
./gradlew assembleXiaomiDebug

运行测试,遇到问题会立即停止
./gradlew test
如果是想运行特点的 flavor
./gradlew testXiaomiDebug , 例子
// 如果遇到问题,还想继续执行
./gradlew test -continue
只针对一个特定的测试类, 例子
./gradlew testDebug –test=”*.LogicTest”

MyApp
|
|—- build.gradle
|—- settings.gradle
|
—- app
|
— build.gradle
例子
这里写图片描述

1. settings.gradle

settings 在初始化阶段被执行,定义包含的模块。
例如这包含 app 和 mylibrary
![这里写图片描述](https://img-blog.csdn.net/20170527221558196?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveXhodWFuZzIwMDg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)

2. 顶层构建文件

. 在项目中,所有模块的配置参数都在顶层的 build.gradle 文件中配置。
如果在 build.gradle 中定义了一些属性,在 manifest 文件中不必再定义,如果构建文件中不包含某个属性,manifest 中该属性就会被用作后备。

. 任务 task
(1). assemble: 为每个构建版本构建一个 APK, 任务默认依赖于 assembleDebug 和 assembleRelease,如果执行命令./gradlew assemble 会生成 release 和 debug 两个 apk.

(2). clean: 删除所有的构建内容;

(3). check: 运行 Lint 检查,如果 Lint 发现一个问题,则可终止构建;

(4). build: 同时运行 assemble 和 check

./gradlew check 会生成一份 Lint 报告,在 app/build/outputs 目录下,名称为 lint-results.html, 该报告包含所有的警告和错误,以及一份详细的说明和一个相关文档的连接。
这里写图片描述

自定义构建

. BuidConfig 的设置
可以在构建类型 buildTypes 中设置 releas 和 debug 版本同的信息, 例如配置不同的 url

    // 构建类型
    buildTypes {
        release {
            minifyEnabled false  // 是否开启混淆
            shrinkResources false  // 自动缩减资源,需要同时与 minifyEnabled 开启
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'   // 混淆配置文件
            // 配置log,在 Release 版本中不打印,
            buildConfigField "boolean", "LOG_CALLS", "false";
            // 配置不同的 URL
            buildConfigField "String", "API_URL", "\"Http://example.com/api\""
        }

        debug {
            buildConfigField "boolean", "LOG_CALLS", "true";
            buildConfigField "String", "API_URL", "\"Http://texst.example.com/api\""
        }
    }

在 java 代码中 BuildConfig.API_URL 引用即可;

. 项目范围的设置
可以在顶层的 build.gradle 中添加一个自定义属性的 ext 代码块

// 自定义属性
ext {
    compileSdkVersion = 25
    buildToolsVersion = "25.0.3"

}

然后在模块的的 build.gradle 中使用 rootProject 来获取属性

android {
    compileSdkVersion rootProject.ext.compileSdkVersion
    buildToolsVersion rootProject.ext.buildToolsVersion
  }

三. 基本自定义构建

1. 依赖仓库

Gradle 支持三种不同的依赖仓库: Maven, Ivy 和静态文件或文件夹.
在顶项目根目录下的 build.gradle

allprojects {
    repositories {
        // jcenter 仓库
        jcenter()
        // Maven Central
        mavenCentral()
        // 本地 Maven 仓库
        mavenLocal()
        // 自有的 Maven 插件, 例子
        maven {
            url "http://repo.acmecorp.com/maven2"
        }
        // 团队自己的仓库
        maven {
            url "http://repo.acmecorp.com/maven2"
            credentials {
                username '****'
                password '*****'
            }
        }
    }
}

四. 依赖管理

1. 本地依赖和项目依赖

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])  // 本地依赖
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })

    // 依赖项目
    compile project(':mylibrary')

    compile 'com.android.support:appcompat-v7:25.3.1'

    // 测试
    testCompile 'junit:junit:4.12'
    // 可以针对特定的 flavor 添加 Junit
    testXiaomiCompile 'junit:junit:4.12'
}

上面我们看到有 compile, 和 testCompile 其实 gradle 可以进行不同的配置
. compile 是默认配置,在编译主应用时包含所有的依赖。

. testComplie 测试依赖

. 针对特定的 variant 的依赖配置,这里的例子是 Xiaomi

.apk, 该依赖只会 被打包到 APK, 而不会添加到编译路径

.provided 与 apk 刚好相反,其依赖不会被打包进 APK.

五. 创建构建 Variant

1. 构建类型

构建类型除了 Release 和 debug 外,可以自定义类型

    // 构建类型
    buildTypes {
        release {
            minifyEnabled false  // 是否开启混淆
            shrinkResources false  // 自动缩减资源,需要同时与 minifyEnabled 开启
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'   // 混淆配置文件
            // 配置log,在 Release 版本中不打印,
            buildConfigField "boolean", "LOG_CALLS", "false";
            // 配置不同的 URL
            buildConfigField "String", "API_URL", "\"Http://example.com/api\""
            // 添加签名信息
//            signingConfig signingConfigs.releas
            // 指定渠道产品特定签名
//            productFlavors.xiaomi.signingConfig signingConfigs.xiaomi
        }

        debug {
            buildConfigField "boolean", "LOG_CALLS", "true";
            buildConfigField "String", "API_URL", "\"Http://texst.example.com/api\""
//            signingConfig signingConfigs.debug
            // 开启测试覆盖率
//            testCoverageEnabled = true
        }

        // 自定义构建类型(命令行可以 ./gradlew assembleStaging)
        staging {
            staging.initWith(buildTypes.debug) // 复制一个已经存在的构建类型所有属性,可以重写,例如下面的 API_URL
            applicationIdSuffix ".staging"  // 生成的 applicationId 变成 包名.staging, 这里是  cash.juzhongke.com.gradledetaildemo.staging
            versionNameSuffix "staging"
            buildConfigField "String", "API_URL", "\"Http://staging.example.com/api\""
//            signingConfig signingConfigs.staging
        }
    }

2. 源集

当创建一个新的构建类型时,Gradle 也会创建一个新的源集。源集目录名称默认和构建类型相同。该目录不是在定义新的构建类型时自动创建的,需要在构建类型使用自定义的源码和资源之前,手动创建该源集目录。
这里写图片描述
上图除了标准的 debug 和 Release ,还有一个额外 staging 构建类型的目录结构。

使用不同源集目录,可以构建类型自己的属性,例如,我们可以定义不同的包名,
这里写图片描述

详情可参考美团技术团队的《美团Android自动化之旅—适配渠道包》

3.product flavor

可以构建不同版本,用于多渠道打包

 // 不同渠道版本
    productFlavors {
        commonsoon {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "commonsoon"]

            // 可以自定义自己的 applicationId
            applicationId 'cash.juzhongke.com.gradledetaildemo.commonsoon'
            versionCode 3
            minSdkVersion 23
        }
        zhushou91 {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "zhushou91"]
        }
        market360 {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "market360"]
        }
        xiaomi {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi"]
        }
        wandoujia {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]
        }
    }

4.构建 Variant

构建 variant 是构建类型和product flavor 结合的结果。点击 Android Studio 左下角的 Build Variant 可以看到
这里写图片描述

5. variant 过滤器

通过 variants 过滤器忽略一些 variant

android {
    // variant 过滤器,这里是忽略 xiaomi release 版本, 在 BuildVariants 中可以看到结果
    android.variantFilter { variant ->
        if (variant.buildType.name.equals('release')){
            variant.getFlavors().each(){ flavor ->
                if (flavor.name.equals('xiaomi')){
                    variant.setIgnore(true);
                }
            }
        }
    }
}

上面的例子是过滤掉 xiaomirelease 版本,在 Build Variant 中,我们就看不到了
这里写图片描述

这里的过滤在 Jenkins 集成的时候特别有用。

6. 签名配置

如果有一个付费版和免费版或针对不同用户的不同应用,可以为每个 flavor

    signingConfigs {
        releas {
            storeFile file(KEY_STORE_FIELD)
            keyAlias
            keyPassword
            storePassword
        }

        debug {
            storeFile file()
            keyAlias
            keyPassword
            storePassword
        }

        staging.initWith(signingConfigs.releas) // staging 和 release 版本一样的签名信息

        // 可以为特定的 flavor 签名
        xiaomi {
            storeFile file()
            keyAlias
            keyPassword
            storePassword
        }
    }

六. 创建任务和插件

加速多模块构建
在根目录下的 gradle.properities

# 并行构建项目, 可以加快构建项目
org.gradle.parallel=true

开启了虽然可以加快构建速度,有时候可能会失败。
使用命令行可以看到开启的信息

$ ./gradlew assemble
Parallel execution is an incubating feature.

七. 高级自定义构建

1. 使用任务来简化 release 过程

如果是配置签名

    signingConfigs {
        releas {
            storeFile file("release.keystore")
            keyAlias "Releasekey"
            keyPassword   "password"
            storePassword  "password"
        }

这样密码已明文方式存放,不安全。可以通过以 task 来构建
在项目的根目录下创建一个 private.properties 文件,然后添加属性;
这里写图片描述

然后在module 目录下的 builde.gradle 添加 task

// 定义一个任务来获取 Release Password
task getReleasePassword << {
    def keypassword = ''
    def storepassword = ''
    def keyalies = ''
    if (rootProject.file('private.properties').exists()){
        Properties properties = new Properties();
        properties.load(rootProject.file('private.properties')
                                      .newDataInputStream())
        keypassword = properties.getProperty('release.password')
        storepassword = properties.getProperty('release.storepassword')
        keyalies = properties.getProperty('release.keyalies')

    }

    // 如果password 为空,private.properties 文件找不到,则询问控制台用户输入
    if (!keypassword?.trim()){
        keypassword = new String(System.console().readPassword("\nWhat's the secret password?"))
    }

    android.signingConfigs.release.keyPassword = keypassword
    android.signingConfigs.release.storePassword = storepassword
    android.signingConfigs.release.keyAlias = keyalies
}

// 运行时才添加,相当于 Hook
tasks.whenTaskAdded { theTask ->
    if (theTask.name.contains("Release")){
        theTask.dependsOn "getReleasePassword"
    }
}

修改后的签名设置

    signingConfigs {
        release {
            storeFile file(KEY_STORE_FIELD)
        }

其中 KEY_STORE_FIELD 是 keystore 的路径,在 gradle.properties 上面设置

KEY_STORE_FIELD = E:\\work\\testkeystore\\gradleDemo.jks

2. 自动命名 apk

在 module 的 build.gradle 中

    // 自动命名 apk
    android.applicationVariants.all { variant ->
        variant.outputs.each { output ->
            def file = output.outputFile
            output.outputFile = new File(file.parent,
                file.name.replace(".apk", "-${variant.versionName}.apk"))
        }
    }

这里在 jenkins 持续集成时会用到。

3. 缩减资源

自动缩减

    buildTypes {
        release {
            minifyEnabled false  // 是否开启混淆
            shrinkResources false  // 自动缩减资源,需要同时与 minifyEnabled 开启
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 
                                  'proguard-rules.pro'   // 混淆配置文件
            }
     }

手动缩减

    defaultConfig {
        applicationId "cash.juzhongke.com.gradledetaildemo"
        minSdkVersion 22
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        //  收到缩减 resConfigs 配置保留资源
        resConfigs "en", "cn", "da"    // 例如保留英语,中文,丹麦的字符串
        resConfigs "hdpi", "xhdpi", "xxhdpi"
    }

注:以上内容摘自《Gradle for Android 中文版》 一书

发布了58 篇原创文章 · 获赞 20 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/yxhuang2008/article/details/72774953