4

With Google of Eclipse relentless abandon and Studio growing, Android developers gradually bowed Studio under feet.
As Studio default compiler mode, Gradle has gradually spread. I was initially attracted by its multi-channel packaging. Next, we will learn about Gradle .

Introduction

Gradle is based on the Groovy language and is Java applications. Automatic construction tool based on DSL(Domain Specific Language)

Gradle collection Ant flexibility and power, but also a collection of Maven dependency management and agreed to create a more effective way to build. With Groovy of DSL and innovative packaging methods, Gradle provides a declarable way and describes all types of construction on the basis of reasonable default values. Gradle has been selected as the build system for many open source projects.

Because Gradle is based on the DSL grammar, if you want to see the configuration of all the options in the build.gradle
DSL Reference

Basic project settings

A Gradle project describes its construction build.gradle file in the project root directory.

Simple Build file

The simplest Android application build.gradle will contain the following configurations:
Project root directory of build.gradle :

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

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

Module in build.gradle :

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.3"
    ...
}
  • buildscript { ... } configured with the code driver at compile time. In this case, it states that the jCenter repository is used. There is also a path to the Maven file that the statement depends on. Here statement contains Android 1.5.0 version of the plug-ins used Gradle Note: This only affects build code to run, not a project. The project needs to declare its own required warehouses and dependencies.
  • apply plugin : com.android.application , declares the use of com.androdi.application plug-in. This is the plug-in needed to Android
  • android{...} configured with all Android construction parameters. By default, only the target version of the compilation and the version of the compilation tool are required.

com.android.application plugin can be used here. If you use the java plugin, an error will be reported.

Directory Structure

module/src/main , because sometimes many people put so libs directory and they will report an error:

  • java/
  • res/
  • AndroidManifest.xml
  • assets/
  • aidl/
  • jniLibs/
  • jni/
  • rs/

Configuration directory structure

If the structure of the project is not standard, you may need to configure it. Android plugin uses a similar syntax, but because it has its own sourceSets , it needs to android code block. The following is from a Eclipse arranged old primary code and the project structure androidTest the sourceSet provided to tests directory examples:

android {
    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
        }

        androidTest.setRoot('tests')
    }
}

Like some people just want to so into libs directory (these people a bit stubborn), it would need to be modified.
Note: Because the old project structure in all the source files ( Java , AIDL and RenderScript ) are placed in the same directory, we need to sourceSet of these new components are set to src directory.

Build Tasks

When declaring the plug-in to the build file, a series of build tasks are usually or automatically created to execute. Java Android regardless of whether 0609fb0c6709df plug-in or 0609fb0c6709e0 plug-in. Android routine tasks of 0609fb0c6709e1 are as follows:

  • assemble generating the contents in the directory of the output
  • check performs all inspection tasks.
  • build performs the tasks of assemble and check
  • clean The task of cleaning up the output

There are at least two output outputs in the Android project: one debug apk and one release apk . They all have their own main tasks to perform the build separately:

  • assemble

    • assembleDebug
    • assembleRelease

Tip: Gradle supports the way of executing task acronyms through the command line. E.g:
On the premise that no other tasks meet aR gradle aR and gradle assembleRelease are the same.

Finally, the build plugin creates build type(debug, release, test) types, as long as they can be installed (signature required).

  • installDebug
  • installRelease
  • uninstallAll

    • uninstallDebug
    • uninstallRelease
    • uninstallDebugAndroidTest

Basic Build customization

Android plugin provides a series of DSL to allow most of the customization directly from the build system.

Manifest integral part

DSL provides a lot of important configuration manifest file, such as:

  • minSdkVersion
  • targetSdkVersion
  • versionCode
  • versionName
  • applicationId
  • testApplicationId
  • testInstrumentationRunnder

Android Plugin DSL Reference provides a complete list of build parameters.

An important function of putting these manifest attributes into the build file is that it can be dynamically set. For example, the version name can be obtained by reading a file or other logic.

def computeVersionName() {
    ...
}

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.1"


    defaultConfig {
        versionCode 12 
        versionName computeVersionName()
        minSdkVersion 16
        targetSdkVersion 23
    }
}

Note: Do not use method names that may conflict with existing given names. E.g. defaultConfig{...} using getVersionName() method will automatically use defaultConfig.getVersionName() to a method starting with the custom.

Build Types

By default, the Android plugin will automatically set the application to have a debug version and a release version.
This is done by calling the BuildType object. Two instances are created by default, one debug instance and one release instance. Android plug-in also allows other Build Types to be customized through other 0609fb0c670dc9. This is set buildTypes

android {
    buildTypes {
        debug {
            applicationIdSuffix ".debug"
        }


        jnidebug {
            initWith(buildTypes.debug)
            applicationIdSuffix ".jnidebug"
            jniDebuggable true
        }
    }
}

The above code does the following:

  • debug with default Build Type :

    • Set its applicationId . Such debug mode and can release mode apk installed on the same phone.
  • Created a new jnidebug of Build Type and set it as a copy debug
  • By allowing JNI components debug and add a new package name suffix to continue to customize the Build Type .

Regardless of whether you use initWith() or use other code blocks, creating a new Build Types is very simple. Create a new element buildTypes

Signature configuration

The following parts are needed to sign the application:

  • A keystore
  • A keystore password
  • A key alias name
  • A key password
  • The store type

By default, there is a debug configuration, set up a debug of keystore , there is a known password. debug keystore position in $HOME/.android/debug.keystore , if not, then he would be created by default. Debug of Build Type will use the signature setting of debug

Of course, you can also create other configurations for customization by using the signingconfigs DSL

android {
    signingConfigs {
        debug {
            storeFile file("debug.keystore")
        }


        myConfig {
            storeFile file("other.keystore")
            storePassword "android"
            keyAlias "androiddebugkey"
            keyPassword "android"
        }
    }


    buildTypes {
        foo {
            signingConfig signingConfigs.myConfig
        }
    }
}

The above setting will debug keystore the location of 0609fb0c670fd2 to the root directory of the project. A new signature configuration is also created, and a new Build Type uses it.

Dependencies, Android Libraries and Multi-project setup

Gradle project can depend on other external binary packages or other Gradle projects.

Local package

A desired configuration dependent external jar package, you need compile add a configuration of dependency . The following configuration adds all jar packages libs directory:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
}


android {
    ...
}

Note: DSL elements dependencies is Gradle API standard elements. Does not belong to the andorid element.
compile configuration is used to compile the main application. All parts of its configuration will be packaged into apk . Of course there are some other configurations:

  • compile: main application
  • androidTestCompile:test application
  • debugCompile:debug Build Type
  • release Compile:release Build Type

Of course we can use the two configurations compile and <buildtype>.compile Creating a new Build Type usually automatically creates a new configuration section based on its name. So as debug version release special version does not apply library very useful.

Remote warehouse

Gradle just uses Maven and Ivy warehouses. But the warehouse must be added to the list, and the Maven or Ivy definition of the dependent warehouse must be declared.

repositories {
     jcenter()
}


dependencies {
    compile 'com.google.guava:guava:18.0'
}


android {
    ...
}

Note: jcenter() is a shortcut setting for the designated warehouse URL Gradle supports remote and local warehouses.
Note: Gradle will directly identify all dependencies. This means that if a dependent library itself depends on other libraries, they will be downloaded together.

Local AAR library
dependencies {
    compile(name:'本地aar库的名字,不用加后缀', ext:'aar')
}
Multi-project settings

Gradle project usually uses multi-project settings to rely on other gradle projects. E.g:

  • MyProject/

    • app/
    • libraries/

      • lib1/
      • lib2/

Gradle will refer to them by the following names:
:app
:libraries:lib1
:libraries:lib2

Each project will have a separate build file, and there will also be a setting.gradle file in the root directory of the project:

  • MyProject/

    • settings.gradle
    • app/

      • build.gradle
    • libraries/

      • lib1/

        - build.gradle      
      • lib2/

        • build.gradle

setting.gradle file is very simple. It specifies which directory is the Gralde project:

include ':app', ':libraries:lib1', ':libraries:lib2'

:app project may depend on other libraries , which can be declared as follows:

dependencies {
     compile project(':libraries:lib1')
}

Library item

The above used :libraries:lib1 and :libraries:lib2 can be Java project, :app project will use their output jar package. But if you need to use android resources, etc., these libraries cannot be ordinary Java projects, they must be Android Library projects.

Create a Library project

Library project and general Android difference is relatively small project, due libraries different building types and applications built, it will use all else to build a plug-in. But inside the plug they use many of the same code, they are made com.android.tools.build.gradle this jar provide package.

buildscript {
    repositories {
        jcenter()
    }


    dependencies {
        classpath 'com.android.tools.build:gradle:1.3.1'
    }
}


apply plugin: 'com.android.library'


android {
    compileSdkVersion 23
    buildToolsVersion "23.0.1"
}
The difference between ordinary items and Library

The main output of the Library .aar package. It combines code (such as jar package or local .so file) and resources ( manifest , res , assets ). Each library can also be individually set to Build Type etc. to specify the generation of different versions of aar .

Lint Support

You can set the operation of lint by specifying the corresponding variable. It can be configured lintOptions

android {
    lintOptions {
        // turn off checking the given issue id's
        disable 'TypographyFractions','TypographyQuotes'

        // turn on the given issue id's
        enable 'RtlHardcoded','RtlCompat', 'RtlEnabled'

        // check *only* the given issue id's
        check 'NewApi', 'InlinedApi'
    }
}

Build variable

One goal of the build system is to be able to create multiple different versions of the same application.

Product flavors

A product flavor can make different build versions for a project. An application can have multiple different falvors to change the generated application.
Product flavors by DSL syntax productFlavors be declared:

android {
    ....


    productFlavors {
        flavor1 {
            ...
        }


        flavor2 {
            ...
        }
    }
}
Build Type + Product Flavor = Build Variant

As we saw before, each Build Type will generate a apk . Product Flavors is the same: the output zombies of the project are all Build Types and Product Flavors . Each combination is called Build Variant . For example, if there debug and release versions Build Types , the above example will generate four kinds Build Variants :

  • Flavor1 - debug
  • Flavor1 - release
  • Flavor2 - debug
  • Flavor2 - release

Not configured flavors project still has Build Variants , it is only with a default flavor/config , no name, which leads to variants list and Build Types Lists is the same.

Product Flavor configuration
android {
    ...


    defaultConfig {
        minSdkVersion 8
        versionCode 10
    }


    productFlavors {
        flavor1 {
            applicationId "com.example.flavor1"
            versionCode 20
         }


         flavor2 {
             applicationId "com.example.flavor2"
             minSdkVersion 14
         }
    }
}

Note that the android.productFlavors.* object ProductFlavor has the same type as android.defaultConfig This means that they have the same attributes.
defaultConfig provides some basic configurations for all flavors flavor has rewritten them. In the above example, these configurations are:

  • flavor1

    • applicationId: com.example.flavor1
    • minSdkVersion: 8
    • versionCode: 20
  • flavor2

    • applicationId: com.example.flavor2
    • minSdkVersion: 14
    • versionCode: 10

Usually, the Build Type configuration will override other configurations. For example, Build Type of applicationIdSuffix will be added to Product Flavor of applicationId .

Finally, just like Build Types , Product Flavors can also have their own dependencies. For example, if there is a single flavors will use some advertising or payment, then the flavors generated by this apk will use the dependency of the advertisement, and the other flavors will not need to be used.

dependencies {
    flavor1Compile "..."
}

BuildConfig

During the compilation phase, Android Studio will generate a BuildConfig , which contains the values of some variables used during compilation. You can watch these values to change the behavior of different variables:

private void javaCode() {
    if (BuildConfig.FLAVOR.equals("paidapp")) {
        doIt();
    else {
        showOnlyInPaidAppDialog();
    }
}

Here are some of the values contained in BuildConfig

  • boolean DEBUG - if the build is debuggable
  • int VERSION_CODE
  • String VERSION_NAME
  • String APPLICATION_ID
  • String BUILD_TYPE - Build Type 's name, for example release
  • String FLAVOR - flavor name, for example flavor1

ProGuard configuration

Android plug-in will default ProGuard plug-ins, and if Build Type used ProGuard of minifyEnabled Properties Open, then by default creates a corresponding task .

android {
    buildTypes {
        release {
            minifyEnabled true
            proguardFile getDefaultProguardFile('proguard-android.txt')
        }
    }

    productFlavors {
        flavor1 {
        }
        flavor2 {
            proguardFile 'some-other-rules.txt'
        }
    }
}

Tasks control

The basic Java project has a series of tasks together to make an output file.
classes task is the task of compiling the Java We can easily get it by using classes build.gradle That is project.tasks.classes .

In the Android project, more compiles task , because their names are generated Build Types and Product Flavors

To solve this problem, the android object has two attributes:

  • applicationVariants - only for the app plugin
  • libraryVariants - only for the library plugin
  • testVariants - for both plugins

These will return a ApplicationVariant , LibraryVariant , TestVariant implementation class object of the DomainObjectCollection
DomainObjectCollection provides a method to obtain all objects directly or indirectly.

android.applicationVariants.all { variant ->
   ....
}

Set the compiled language version

You can use the compileOptions code block to set the language version used during compilation. The default is based on the value of compileSdkVersion

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_6
        targetCompatibility JavaVersion.VERSION_1_6
    }
}

Resource Shrinking

Gradle build system supports resource cleanup: useless resources are automatically removed from the built application. Not only will the unused resources in the project be removed, but also the resources in the class library from the project will be removed. Note that resource cleanup can only be used in conjunction with code cleanup (for example, ProGuad ). This is why it can remove the useless resources of the dependent libraries. Generally, all resources in the class library are used, and only after the useless code in the class library is removed will these resources become useless resources without code references.

android {
    ...

    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

xiangzhihong
5.9k 声望15.3k 粉丝

著有《React Native移动开发实战》1,2,3、《Kotlin入门与实战》《Weex跨平台开发实战》、《Flutter跨平台开发与实战》1,2和《Android应用开发实战》