Skip to content

Gradle 基础自定义构建

win7 Android Studio 2.1.3

基础自定义构建 Basic Build Customization

本章目的

  • 理解Gradle文件
  • build tasks入门
  • 自定义构建

理解Gradle文件

在Android Studio中新建一个项目后,会自动创建3个Gradle文件。

MyApp
├── build.gradle
├── settings.gradle
└── app
    └── build.gradle

每个文件都有自己的作用

settings.gradle文件

新建工程的settings文件类似下面这样

include ':app'

Gradle为每个settings文件创建Settings对象,并调用其中的方法。

The top-level build file 最外层的构建文件

能对工程中所有模块进行配置。如下

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.1.3'

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

allprojects {
    repositories {
        jcenter()
        maven { url "https://jitpack.io" }
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

buildscript代码块是具体配置的地方,引用JCenter仓库。 本例中,一个仓库代表着依赖库,换句话说是app可以从中下载使用库文件。
JCenter是一个有名的 Maven 仓库。

dependencies代码块用来配置依赖。上面注释说明了,不要在此添加依赖,而应该到独立的模块 中去配置依赖。

allprojects能对所有模块进行配置。

模块中的build文件

模块中的独立配置文件,会覆盖掉top-level的build.gradle文件

apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.2"

    defaultConfig {
        applicationId "com.xxx.rust.newproj"
        minSdkVersion 18
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:25.1.0'
}

下面来看3个主要的代码块。

plugin

第一行应用了Android 应用插件。Android插件由Google团队开发维护。该插件提供构建,测试,打包应用和模块需要的所有的task。

android

最大的一个区域。defaultConfig区域对app核心进行配置,会配置覆盖AndroidManifest.xml中的配置。

applicationId复写掉manifest文件中的包名。但applicationId和包名有区别。
manifest中的包名,在源代码和R文件中使用。所以package name在android studio中理解为一个查询类的路径比较合理。
applicationId在Android系统中是作为应用的唯一标识,即在一个Android设备中所有的应用程序的applicationId都是唯一的。

dependencies

是Gradle标准配置的一部分。 Android中用来配置使用到的库。

定制化构建 Customizing the build

BuildConfig and resources

自从SDK17以来,构建工具会生成一个BuildConfig类,包含着静态变量DEBUG和一些信息。
如果你想在区分debug和正式版,比如打log,这个BuildConfig类很有用。
可以通过Gradle来扩展这个类,让它拥有更多的静态变量。

以NewProj工程为例,app\build.gradle

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.2"

    defaultConfig {
        applicationId "com.xxx.rust.newproj"
        minSdkVersion 18
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        debug {
            buildConfigField("String", "BASE_URL", "\"http://www.baidu.com\"")
            buildConfigField("String", "A_CONTENT", "\"debug content\"")
            resValue("string", "str_version", "debug_ver")
        }
        release {
            buildConfigField("String", "BASE_URL", "\"http://www.qq.com\"")
            buildConfigField("String", "A_CONTENT", "\"release content\"")
            resValue("string", "str_version", "release_ver")

            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

上面的buildConfigFieldresValue在编译后,能在源代码中使用
注意上面那个转义的分号不可少;注意里面的大小写,这里传入的参数就像是直接填入的代码一样

下面是编译后生成的BuildConfig文件,可以看到buildConfigField的东西已经在里面了

public final class BuildConfig {
  public static final boolean DEBUG = Boolean.parseBoolean("true");
  public static final String APPLICATION_ID = "com.xxx.rust.newproj";
  public static final String BUILD_TYPE = "debug";
  public static final String FLAVOR = "";
  public static final int VERSION_CODE = 1;
  public static final String VERSION_NAME = "1.0";
  // Fields from build type: debug
  public static final String A_CONTENT = "debug content";
  public static final String BASE_URL = "http://www.baidu.com";
}

resValue会被添加到资源文件中

mTv2.setText(R.string.str_version);

通过 build.gradle 增加获取 applicationId 的方式

模块build.gradle中添加属性applicationId,会被编译到BuildConfig中

project.afterEvaluate {
    project.android.applicationVariants.all { variant ->
        def applicationId = [variant.mergedFlavor.applicationId, variant.buildType.applicationIdSuffix].findAll().join()
    }
}

在代码中可以直接使用

String appID = BuildConfig.APPLICATION_ID;

获取时间的方法

模块build.gradle中添加方法getTime(),并在buildTypes中添加域。

// 获取当前时间
static def getTime() {
    String timeNow = new Date().format('YYYYMMdd-HHmmss')
    return timeNow
}

android {
    // ...
    buildTypes {
        debug {
            buildConfigField "String", "BUILD_TIME", "\"" + getTime() + "\""
        }
        release {
            buildConfigField "String", "BUILD_TIME", "\"" + getTime() + "\""
            // ...
        }
    }
}

BuildConfig.java中得到这个域。

  // Fields from build type: debug
  public static final String BUILD_TIME = "20180912-100335";

修改release apk文件名的方法

gradle版本3.1.4。使用了上面的方法getTime()

android {
    // ...
    // 修改release的apk名字
    applicationVariants.all { variant ->
        variant.outputs.all {
            if (variant.buildType.name == 'release') {
                outputFileName = "xxx_release_${defaultConfig.versionName}_${getTime()}.apk"
            }
        }
    }
}

以前的方法可能会遇到问题:Cannot set the value of read-only property 'outputFile' for ApkVariantOutputImpl_Decorated
参考:https://stackoverflow.com/questions/44239235/android-gradle-3-0-0-alpha2-plugin-cannot-set-the-value-of-read-only-property

工程范围的设置

如果一个工程中有多个模块,可以对整个工程应用设置,而不用去修改每一个模块。

NewProj\build.gradle

allprojects {
    repositories {
        jcenter()
    }
}

ext {
    compileSDKVersion = 25
    local = 'Hello from the top-level build'
}

每一个build.gradle文件都能定义额外的属性,在ext代码块中。

在一个模块的libmodule\build.gradle文件中,可以引用rootProject的ext属性

android {
    compileSdkVersion rootProject.ext.compileSDKVersion
    buildToolsVersion "25.0.2"
    // ....
}

工程属性 Project properties

定义properties的地方 * ext代码块 * gradle.properties文件 * 命令行 -P 参数

工程build.gradle文件

ext {
    compileSDKVersion = 25
    local = 'Hello from the top-level build'
}

/**
 * Print properties info
 */
task aPrintSomeInfo {
    println(local)
    println('project dir: ' + projectDir)
    println(projectPropertiesFileText)
}

task aPrintAllProperites() {
    println('\nthis is aPrintAllProperites task\n')
    Iterator pIt = properties.iterator()
    while (pIt.hasNext()) {
        println(pIt.next())
    }
}

gradle.properties文件中增加

projectPropertiesFileText = Hello there from gradle.properties

在as的Gradle栏上双击执行aPrintSomeInfo,会连带下一个task也执行

13:08:10: Executing external task 'aPrintSomeInfo'...
Hello from the top-level build
project dir: G:\openSourceProject\NewProj
Hello there from gradle.properties

this is aPrintAllProperites task
......
BUILD SUCCESSFUL

Total time: 1.025 secs
13:08:11: External task execution finished 'aPrintSomeInfo'.

参考:Gradle for Android Kevin Pelgrims