美文网首页好好找job架构我爱编程
Android Gradle配置快速入门

Android Gradle配置快速入门

作者: jzj1993 | 来源:发表于2018-02-24 16:22 被阅读651次

    说明

    本文主要介绍和Gradle关系密切、相对不容易理解的配置,偏重概念介绍。部分内容是Android特有的(例如ProductFlavor),其他内容则是所有Gradle工程都相同或类似的知识。

    对于一些常规且相对简单的配置项,例如签名配置SigningConfig,不做具体介绍。而部分比较复杂且不太常用的内容,例如Manifest的具体合并规则,只做简单说明,并给出深入学习的相关链接,读者可自行阅读。

    文章主要基于Gradle V3.3 + Android Gradle Plugin V2.3 + Android Studio 2.3,在后续版本升级后部分内容可能会改变。

    文中的内容,有些是根据源码分析得到,有些是参考了官方文档,还有些参考了网上的文章。如有不正确的地方,欢迎指正。

    关于Gradle DSL的语法原理和开发相关知识,可参考我的另一篇文章

    Gradle开发快速入门——DSL语法原理与常用API介绍
    http://www.paincker.com/gradle-develop-basics

    基本问题

    开始看本文前,可以思考下面这些关于Gradle的基本问题。文中会对这些问题进行解释。

    1. settings.gradle有什么作用?

    2. repositories {}语句块的作用?

    3. buildscriptallprojects的区别?

    4. ProductFlavor和BuildType的区别?

    5. 依赖冲突的原因和常见解决思路?

    6. classpath 'com.android.tools.build:gradle:2.2.3',有什么作用?

    7. gradle/wrapper/gradle-wrapper.properties中的这句有什么作用?
      distributionUrl=https://services.gradle.org/distributions/gradle-2.14.1-all.zip

    8. 命令行中,gradle assemble、gradle assembleDebug、gradle build 的关系?

    9. Android Studio环境下,Gradle Sync操作做了什么工作?

    Gradle

    Gradle是一个基于Groovy语言的强大的构建系统,Groovy则是在Java基础上扩展的、运行在JVM上的一种脚本语言。

    通过丰富的插件扩展,Gradle可以支持Java、JavaWeb、Groovy、Android等工程的编译,同时可以很方便的从Maven、Ant等迁移过来。

    C系列语言也有相应的Gradle插件,但Gradle支持最好的还是Java系列语言。

    Gradle也是一个命令行可执行程序,可从官网下载Gradle,可执行文件位于bin/gradle

    执行Gradle任务的过程,主要就是在运行Java/Groovy代码。编译期间如果有代码抛出了异常,就会中断编译过程。

    在Android Studio中开发时,编译就是基于Gradle实现的。Android Studio中内置了Gradle。

    Gradle官网
    https://gradle.org/

    Gradle Wrapper

    用IDEA/Android Studio创建基于Gradle的工程时,默认会在工程根目录创建GradleWrapper,包括gradlew可执行脚本和gradle/wrapper文件夹,其中指定了和工程配套的gradle版本。

    在工程根目录下直接执行./gradlew,会自动将参数传给wrapper指定版本的gradle,执行对应的命令;如果本机还没有该版本的gradle,则会先自动下载。

    工程配置和Gradle版本通常需要对应,不正确的Gradle版本可能无法正常编译工程,因此推荐使用GradleWrapper执行Gradle命令。

    gradle/wrapper/gradle-wrapper.properties文件,指定了gradle版本、下载地址、下载的文件存放位置(Mac系统中默认在~/.gradle/wrapper/dists目录)。此文件内容示例:

    distributionBase=GRADLE_USER_HOME
    distributionPath=wrapper/dists
    zipStoreBase=GRADLE_USER_HOME
    zipStorePath=wrapper/dists
    distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
    

    在Android Studio/IDEA中,可通过Preferences - Build, Execution, Deployment - Gradle,设置Project-level settings中Use default gradle wrapper,指定Android Studio使用工程配置的Gradle Wrapper。

    DSL、DSL Reference

    Gradle使用Groovy语言封装了一整套API,通常把这套API称为DSL(Domain-Specific Languages,领域特定语言)。

    通常在我们配置Gradle编译参数时,所写的gradle脚本从形式上来看,像是一门有着特殊语法格式的语言。

    Gradle封装的DSL,按照固定格式用很简单的语法就能实现很复杂的配置,大大简化了配置工作。另一方面,也正是由于封装的非常完善,想深入学习Gradle,会感觉无从下手。

    可以通过DSL Reference文档查看Gradle DSL支持的语法配置项。例如:

    Gradle DSL Reference(Gradle原生支持的DSL配置)
    https://docs.gradle.org/current/dsl/

    Android Plugin DSL Reference(Android的DSL配置)
    http://google.github.io/android-gradle-dsl/current/

    关于Gradle DSL的语法原理和开发相关知识,可参考我的另一篇文章

    Gradle开发快速入门——DSL语法原理与常用API介绍
    http://www.paincker.com/gradle-develop-basics

    Project、RootProject、SubProject (Module)

    Project是Gradle中的基本概念之一,即一个工程。一个工程可以包含多个SubProject,也称为Module,最顶层的工程也称为RootProject。

    一个标准的Android工程,文件结构如下。

    • 每个build.gradle对应一个Project,最外层的是RootProject,里面的app是SubProject。

    • settings.gradle不是必须的,一般在包含子工程时就需要用这个文件指定,即我们通常所见的include ':app'脚本。

    • 这里的':app'就是子工程的名字,通常和文件夹名称对应。

    settings.gradle
    build.gradle
    app
        build.gradle
    

    StartParameter

    Gradle执行时有一些称为StartParameter的参数,StartParameter可在命令行设置,可通过gradle --help查看。例如:

    1. --quiet,执行过程中,只显示Error级别的Log。
    2. --stacktrace,执行过程中,输出所有Exception的stacktrace。
    3. --full-stacktrace,执行过程中,输出所有Exception的完整stacktrace。
    4. --no-daemon,不使用Deamon。Deamon是用于加速Gradle执行的后台进程,有些情况下使用Deamon会有问题(可参考 https://docs.gradle.org/current/userguide/gradle_daemon.html
    5. --offline,离线模式,不使用网络资源。

    在命令行可通过-P参数传入projectProperties,并在Gradle脚本中获取

    # 命令行传入projectProperties
    ./gradlew clean -Pkey=value
    
    // gradle脚本中获取projectProperties
    print gradle.startParameter.projectProperties.get('key')
    

    还可以通过-D参数传入systemPropertiesArgs,并在Gradle脚本中获取

    # 命令行传入systemPropertiesArgs
    ./gradlew clean -Dkey=value
    
    // gradle脚本中获取systemPropertiesArgs
    print gradle.startParameter.systemPropertiesArgs.get('key')
    

    gradle.properties

    Properties文件格式可由java.util.Properties解析,包含若干键值对,类似HashMap<String,String>

    Gradle运行时会自动读取gradle.properties文件并引用其中的属性。有多个位置可以放gradle.properties文件,按优先级从低到高如下:

    • Project所在目录(即build.gradle所在目录),包括RootProject和SubProject
    • GradleHome目录(Mac中默认为~/gradle
    • 通过gradle命令行-D参数指定的Property

    在gradle.properties文件中,一些保留Key可用于配置Gradle运行环境,例如org.gradle.daemon用于设置GradleDeamon,org.gradle.logging.level用于设置Gradle的Log级别等。

    详情可参考
    https://docs.gradle.org/current/userguide/build_environment.html

    除了保留Key以外,其他Key都可以作为变量用于配置工程。例如在Project目录的gradle.properties中统一定义Support包的版本号,然后在build.gradle中使用定义的变量如下。

    SUPPORT_LIBRARY_VERSION=23.4.0
    
    dependencies {
        compile "com.android.support:support-v4:${SUPPORT_LIBRARY_VERSION}"
        compile "com.android.support:appcompat-v7:${SUPPORT_LIBRARY_VERSION}"
        compile "com.android.support:design:${SUPPORT_LIBRARY_VERSION}"
        compile "com.android.support:recyclerview-v7:${SUPPORT_LIBRARY_VERSION}"
    }
    

    Gradle Task

    Gradle以Task(任务)的形式组织每一步操作,每个Task执行一个原子操作(例如把Java编译成class文件、把class打成jar/dex文件、APK签名等)。

    每个Project包含若干Task,Task之间存在依赖关系,执行一个Task前,会先执行它所依赖的Task。

    每个Task有自己的名字(例如'assemble'),结合其所属Project的名字(例如':app'),可以组成完整名(例如':app:assemble')。

    Gradle内建了一个名为tasks的Task,可以列举Project中的所有Task。

    执行Task,查看Project中的所有Task

    执行Task时,直接把Task名称传给gradle即可。

    如果下载了Gradle并配置了环境变量,则可在工程根目录执行:

    gradle tasks
    

    更推荐的做法,是在工程根目录下调用GradleWrapper执行:

    ./gradlew tasks
    

    执行结果如下(省略了部分输出):

    $ ./gradlew tasks
    :tasks
    
    ------------------------------------------------------------
    All tasks runnable from root project
    ------------------------------------------------------------
    
    Android tasks
    -------------
    androidDependencies - Displays the Android dependencies of the project.
    signingReport - Displays the signing info for each variant.
    sourceSets - Prints out all the source sets defined in this project.
    
    Build tasks
    -----------
    assemble - Assembles all variants of all applications and secondary packages.
    assembleAndroidTest - Assembles all the Test applications.
    assembleDebug - Assembles all Debug builds.
    assembleRelease - Assembles all Release builds.
    build - Assembles and tests this project.
    buildDependents - Assembles and tests this project and all projects that depend on it.
    buildNeeded - Assembles and tests this project and all projects it depends on.
    classes - Assembles main classes.
    clean - Deletes the build directory.
    cleanBuildCache - Deletes the build cache directory.
    compileDebugAndroidTestSources
    compileDebugSources
    compileDebugUnitTestSources
    compileReleaseSources
    compileReleaseUnitTestSources
    jar - Assembles a jar archive containing the main classes.
    mockableAndroidJar - Creates a version of android.jar that's suitable for unit tests.
    testClasses - Assembles test classes.
    
    Build Setup tasks
    -----------------
    init - Initializes a new Gradle build. [incubating]
    wrapper - Generates Gradle wrapper files. [incubating]
    
    Documentation tasks
    -------------------
    javadoc - Generates Javadoc API documentation for the main source code.
    
    Help tasks
    ----------
    buildEnvironment - Displays all buildscript dependencies declared in root project 'AndroidLint'.
    components - Displays the components produced by root project 'AndroidLint'. [incubating]
    dependencies - Displays all dependencies declared in root project 'AndroidLint'.
    dependencyInsight - Displays the insight into a specific dependency in root project 'AndroidLint'.
    dependentComponents - Displays the dependent components of components in root project 'AndroidLint'. [incubating]
    help - Displays a help message.
    model - Displays the configuration model of root project 'AndroidLint'. [incubating]
    projects - Displays the sub-projects of root project 'AndroidLint'.
    properties - Displays the properties of root project 'AndroidLint'.
    tasks - Displays the tasks runnable from root project 'AndroidLint' (some of the displayed tasks may belong to subprojects).
    
    Install tasks
    -------------
    installDebug - Installs the Debug build.
    installDebugAndroidTest - Installs the android (on device) tests for the Debug build.
    uninstallAll - Uninstall all applications.
    uninstallDebug - Uninstalls the Debug build.
    uninstallDebugAndroidTest - Uninstalls the android (on device) tests for the Debug build.
    uninstallRelease - Uninstalls the Release build.
    
    Verification tasks
    ------------------
    check - Runs all checks.
    connectedAndroidTest - Installs and runs instrumentation tests for all flavors on connected devices.
    connectedCheck - Runs all device checks on currently connected devices.
    connectedDebugAndroidTest - Installs and runs the tests for debug on connected devices.
    deviceAndroidTest - Installs and runs instrumentation tests using all Device Providers.
    deviceCheck - Runs all device checks using Device Providers and Test Servers.
    lint - Runs lint on all variants.
    lintDebug - Runs lint on the Debug build.
    lintRelease - Runs lint on the Release build.
    test - Run unit tests for all variants.
    testDebugUnitTest - Run unit tests for the debug build.
    testReleaseUnitTest - Run unit tests for the release build.
    
    To see all tasks and more detail, run gradlew tasks --all
    
    To see more detail about a task, run gradlew help --task <task>
    
    BUILD SUCCESSFUL
    
    Total time: 1.367 secs
    

    执行多个Task

    如果需要先后执行多个Task,例如tasks和clean,将它们依次传给gradle即可:

    ./gradlew tasks clean
    

    排除特定Task

    使用gradle的-x--exclude-task参数,可指定执行Task时排除特定Task。例如:

    ./gradlew build -x check
    

    执行SubProject中的Task

    如果想执行子工程':app'中的Task,可使用Task的完整名执行

    ./gradlew :app:tasks
    

    也可以切换到子工程目录执行,但切换当前目录会影响Gradle脚本中的相对路径,不推荐。

    cd app
    gradle tasks
    

    Task参数、查看Task详细信息

    Task可以定义参数,可在执行时从命令行传入。例如Gradle内建了一个叫“help”的Task,带有一个--task参数,可以用于查看一个Task的详细信息。

    查看“tasks”这个Task的详细信息,就可以执行命令如下。其中会显示一个Task的名称、类型、参数、详细介绍、分组等。

    $ ./gradlew help --task tasks
    :help
    Detailed task information for tasks
    
    Path
         :tasks
    
    Type
         TaskReportTask (org.gradle.api.tasks.diagnostics.TaskReportTask)
    
    Options
         --all     Show additional tasks and detail.
    
    Description
         Displays the tasks runnable from root project 'GradleStudy' (some of the displayed tasks may belong to subprojects).
    
    Group
         help
    
    BUILD SUCCESSFUL
    
    Total time: 1.051 secs
    

    一些常用GradleTask

    • clean: 清除build目录编译生成的文件 (Deletes the build directory.)
    • assemble:编译工程 (Assembles the outputs of this project. [jar])
    • build:编译并测试工程 (Assembles and tests this project. [assemble, check])
    • test:单元测试等 (Runs the unit tests. [classes, testClasses])
    • check:测试工程,包含test (Runs all checks. [test])
    • wrapper:生成GradleWrapper文件 (Generates Gradle wrapper files. [incubating])
    • help: 帮助信息 (Displays a help message.)
    • tasks:查看Project的所有Task (Displays the tasks runnable from root project 'Xxx'.)
    • dependencies:查看Project的依赖 (Displays all dependencies declared in root project 'Xxx'.)
    • projects: 查看SubProject (Displays the sub-projects of root project 'Xxx'.)

    查看Task依赖树

    每个Task都会依赖若干Task,这些Task又会依赖别的Task,所有Task就会形成一个依赖树。

    为了更加直观的学习,可以在app/build.gradle中添加如下的简单脚本,让Gradle输出Task的依赖树。

    方法printDependencies通过递归的方式,输出每个Task依赖的Task。afterEvaluate语句块中,先找到assembleDebug这个Task,然后调用printDependencies输出其依赖树。由于Android中有大量Task依赖,打印出所有Task需要很久,所以这里限制了最大递归深度为3。

    def printDependencies(Task task, String prefix, int depth, int maxDepth) {
        println prefix + task.project.name + ':' + task.name
        def tasks = task.getTaskDependencies().getDependencies(task)
        if (depth < maxDepth - 1) {
            tasks.each { t ->
                printDependencies(t, prefix + '\t', depth + 1, maxDepth)
            }
        } else {
            if (tasks.size() > 0) {
                println prefix + '\t' + "(${tasks.size()} child tasks...)"
            }
        }
    }
    
    afterEvaluate {
        println '==============================='
        def buildTask = tasks.findByName('assembleDebug')
        printDependencies(buildTask, '', 0, 3)
        println '==============================='
    }
    

    执行任意Gradle任务,例如clean,部分输出内容如下。

    $ ./gradlew clean
    ===============================
    app:assembleDebug
        app:packageDebug
            app:processDebugResources
                (2 child tasks...)
            app:compileDebugJavaWithJavac
                (4 child tasks...)
            app:mergeDebugAssets
                (2 child tasks...)
            app:validateSigningDebug
            app:transformNativeLibsWithMergeJniLibsForDebug
                (3 child tasks...)
            app:transformResourcesWithMergeJavaResForDebug
                (2 child tasks...)
            app:transformClassesWithDexForDebug
                (2 child tasks...)
        app:compileDebugSources
            app:compileDebugNdk
                (1 child tasks...)
            app:compileDebugJavaWithJavac
                (4 child tasks...)
    ===============================
    :clean
    :app:clean
    
    BUILD SUCCESSFUL
    
    Total time: 0.975 secs
    

    buildscript与allprojects

    在RootProject的build.gradle中,经常会看到buildscript和allprojects两个语句块,并且里面都定义了一些相同的东西。

    buildscript,顾名思义,是编译脚本,也就是说编译一个工程时需要的配置,例如常会看到下面这样的脚本,表示编译时要用到Android Gradle Plugin。

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

    allprojects,则用于配置所有project,包括SubProject,这里面的配置的东西,则是工程代码需要的东西,例如依赖的各种开源库等。

    allprojects {
        repositories {
            jcenter()
        }
    }
    

    关于编译与Groovy

    编译就是将程序源码转换成可执行文件或中间代码的过程。具体到Java,就是将.java代码文件变成.class或者进一步打包成.jar的过程。

    Gradle基于Groovy,Groovy是在Java基础上扩展的脚本语言。Groovy有和解释型语言一样的特性,可以直接从源码运行而不需要提前编译。但实际运行过程中,也是先转换成Java的class文件,再运行在JVM上的。

    在buildscript的dependencies中,通过classpath语句引用一些编译好的jar包,Gradle在执行时就会将其下载并加入Java的classpath,其中的class在编译时就可以被调用,运行在电脑或云主机上。

    Gradle Plugin

    Gradle之所以是个强大的构建系统,很重要的一点在于其完善的插件支持。

    Gradle内建了Java、Groovy等插件,除此之外,还可以在Gradle提供的一整套API基础上开发插件,实现各种编译打包工作。

    Gradle Android Plugin

    在Android开发编译时,会有很多Android相关的配置,这些都是由Gradle的Android插件实现的。

    在buildscript中,通过dependencies引入了Gradle Android插件:

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

    在app/build.gradle中,通过apply的方式,应用了Android插件:

    // 对于Android Application(APK)
    apply plugin: 'com.android.application'
    
    // 对于Android Library(AAR)
    apply plugin: 'com.android.library'
    

    应用了Android插件后,即可在app/build.gradle中使用插件定义的Android相关DSL了:

    android {
        compileSdkVersion 24
        buildToolsVersion '25.0.2'
    
        defaultConfig {
            applicationId "com.paincker.lint.demo"
            minSdkVersion 15
            targetSdkVersion 25
            versionCode 1
            versionName "1.0"
        }
    }
    

    Repositories

    很多从Eclipse转到Android Studio的开发者,刚开始都对Gradle自动下载依赖包的功能印象深刻。

    Gradle的依赖管理完全兼容Maven和Ivy,常使用Maven仓库来实现依赖管理,当Library打包完成后上传到Maven仓库,Gradle则会从Maven仓库下载需要的依赖。

    Repository就是用来指定所需要的Maven仓库。除了常见的jcenter(),mavenCentral(),还可以指定本地搭建的Maven仓库、指定URL的Maven仓库等,例如国内一些Maven仓库镜像,以及很多公司内部私有的Maven仓库等。

    repositories {
        jcenter()
        mavenCentral()
        maven { url 'http://maven.oschina.net/content/groups/public/' }
        ivy { url "http://repo.mycompany.com/repo" }
        localRepository { dirs 'lib' }
        maven {
            url "sftp://repo.mycompany.com:22/maven2"
            credentials {
                username 'user'
                password 'password'
            }
        }
    }
    

    Dependencies

    Gradle依赖管理官方文档
    https://docs.gradle.org/current/userguide/dependency_management.html

    DependencyNotation

    DependencyNotation用于描述要依赖的模块。

    外部依赖

    通常用group:name:version:classifier@ext的形式表示。其中group通常用包名,name表示实际的名字,version表示版本,classifier在Android中是ProductFlavor和BuildType的组合(后面会介绍),ext则表示扩展名。

    compile "org.gradle.test.classifiers:service:1.0:jdk15@jar"
    
    compile group: 'org.gradle.test.classifiers', name: 'service', version: '1.0', classifier: 'jdk15'
    

    Project依赖

    compile project(':someProject')
    

    文件依赖

    dependencies {
      //declaring arbitrary files as dependencies
      compile files('hibernate.jar', 'libs/spring.jar')
    
      //putting all jars from 'libs' onto compile classpath
      compile fileTree('libs')
    }
    

    参考官方文档
    https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.dsl.DependencyHandler.html

    依赖传递(transitive)

    Gradle依赖项可配置transitive属性,表示是否递归解析此模块的依赖项,默认为true。

    compile('org.hibernate:hibernate:3.0.5') {
        transitive = true
    }
    

    依赖树查看

    每个模块都会依赖若干模块,这些模块又分别依赖其他模块,形成一个依赖树。Gradle提供了名为dependencies的Task,可查看Project的依赖树,执行效果如下(省略了部分输出)。

    $ ./gradlew :app:dependencies
    
    ------------------------------------------------------------
    Project :app
    ------------------------------------------------------------
    
    compile - Classpath for compiling the main sources.
    +--- com.android.support:appcompat-v7:24.0.0
    |    +--- com.android.support:support-v4:24.0.0
    |    |    \--- com.android.support:support-annotations:24.0.0
    |    +--- com.android.support:support-vector-drawable:24.0.0
    |    |    \--- com.android.support:support-v4:24.0.0 (*)
    |    \--- com.android.support:animated-vector-drawable:24.0.0
    |         \--- com.android.support:support-vector-drawable:24.0.0 (*)
    \--- com.android.support.constraint:constraint-layout:1.0.2
         \--- com.android.support.constraint:constraint-layout-solver:1.0.2
    

    Artifact

    Artifact可以理解成一个模块的具体实现。一个依赖项可以包含多个Artifact,例如依赖项com.demo:mymodule:library:1.0中可以包含多个不同格式、BuildType的Artifact:

    • library-1.0-debug.jar
    • library-1.0-release.jar
    • library-1.0-debug.aar
    • library-1.0-release.aar

    Module Descriptor、POM文件

    Gradle是如何获取到一个模块的依赖项的呢?

    在Maven或Ivy仓库中,模块的依赖信息并不包含在Artifact文件中,而是通过ModuleDescriptor文件声明的。

    以阿里的Maven仓库为例,用浏览器打开链接
    http://maven.aliyun.com/nexus/content/groups/public/com/android/tools/build/gradle/2.3.0/

    可以看到com.android.tools.build:gradle:2.3.0这个模块所包含的文件。其中sources.jar为代码源文件,pom文件则为ModuleDescriptor。

    • gradle-2.3.0-sources.jar
    • gradle-2.3.0-sources.jar.md5
    • gradle-2.3.0-sources.jar.sha1
    • gradle-2.3.0.jar
    • gradle-2.3.0.jar.md5
    • gradle-2.3.0.jar.sha1
    • gradle-2.3.0.pom
    • gradle-2.3.0.pom.md5
    • gradle-2.3.0.pom.sha1

    在Maven仓库中,模块的POM文件可以指定默认的Artifact,并声明其依赖项;不支持分别声明多个Artifact的依赖项。AAR工程配置多版本发布的时候,需要考虑这一特性。

    If you declare a module dependency, Gradle looks for a module descriptor file (pom.xml or ivy.xml) in the repositories. If such a module descriptor file exists, it is parsed and the artifacts of this module (e.g. hibernate-3.0.5.jar) as well as its dependencies (e.g. cglib) are downloaded. If no such module descriptor file exists, Gradle looks for a file called hibernate-3.0.5.jar to retrieve. In Maven, a module can have one and only one artifact. In Gradle and Ivy, a module can have multiple artifacts. Each artifact can have a different set of dependencies.

    多Artifact的依赖处理、Artifact only notation

    Gradle在处理依赖时,对于有多个Artifact的Maven模块,可在DependencyNotation中声明需要的Artifact,没有声明则使用POM文件指定的默认版本,POM中也没有指定则默认使用和module名一致的jar包。

    当使用“@”指定了所依赖模块的Artifact,称为Artifact only notation,此时Gradle只会下载对应的Artifact,而不会下载其依赖,此时可能就需要设置transitive属性。

    compile('com.facebook.fresco:fresco:0.10.0@aar') {
        transitive = true
    }
    

    If no module descriptor file can be found, Gradle by default downloads a jar with the name of the module. But sometimes, even if the repository contains module descriptors, you want to download only the artifact jar, without the dependencies. [11] And sometimes you want to download a zip from a repository, that does not have module descriptors. Gradle provides an artifact only notation for those use cases - simply prefix the extension that you want to be downloaded with '@' sign.

    依赖冲突分解

    依赖项很多时,依赖项之间经常会发生冲突。例如多个SDK分别依赖了不同版本的AppCompat,就可能导致冲突。Gradle提供了一些API可以用来处理依赖冲突。

    常见的依赖冲突解决思路可参考:

    Gradle依赖项学习总结,dependencies、transitive、force、exclude的使用与依赖冲突解决
    http://www.paincker.com/gradle-dependencies

    ProductFlavor、BuildType与Build Variant

    Android中定义了ProductFlavor和BuildType的DSL。

    ProductFlavor

    ProductFlavor可以实现一套代码编译成不同的版本,版本之间差异比较小,例如开发版本、测试版本、线上版本;或是发布到某些应用市场的定制版本(例如需要修改一些资源文件)等。

    ProductFlavor中包含了一些应用相关的配置,例如minSdkVersion,versionCode等。下面的代码,就是在对默认的ProductFlavor做配置。

    android {
        defaultConfig {
            applicationId "com.paincker.gradle.demoapplication"
            minSdkVersion 15
            targetSdkVersion 24
            versionCode 1
            versionName "1.0"
        }
    }
    

    可以在ProductFlavors中定义新的Flavor并进行配置,覆盖DefaultProductFlavor中的相应配置。

    android {
        productFlavors {
            myflavor {
                minSdkVersion 20
            }
        }
    }
    

    ProductFlavor还支持多维度(Multi-flavors),每个纬度之间可以进行组合。例如下面的示例,flavor有abi和version两个纬度,最后就会有6种组合:

    • x86-freeapp
    • arm-freeapp
    • mips-freeapp
    • x86-paidapp
    • arm-paidapp
    • mips-paidapp
    android {
        ...
        flavorGroups "abi", "version"
        productFlavors {
            freeapp {
                flavorGroup "version"
                ...
            }
            paidapp {
                flavorGroup "version"
                ...
            }
    
            x86 {
                flavorGroup "abi"
                ...
            }
            arm {
                flavorGroup "abi"
                ...
            }
            mips {
                flavorGroup "abi"
                ...
            }
        }
    }
    

    参考:多定制的变种版本
    https://flyouting.gitbooks.io/gradle-plugin-user-guide-cn/content/multi-flavor_variants.html

    BuildType

    BuildType本身是软件开发中的通用概念,表示编译版本。

    Android中定义了自己的BuildType接口,其中包含了一些编译相关的配置,例如debuggable(是否可调试)、minifyEnable(是否开启Proguard)等。

    可以在buildTypes中配置支持的BuildType如下。即使不做任何配置,默认也会有Debug和Release两个BuildType,且分别包含了一套默认值,例如Debug的debuggable参数默认为true,而Release的debuggable参数默认为false。

    android {
        buildTypes {
            debug {
            }
            develop {
                debuggable false
                minifyEnabled false
            }
            release {
                debuggable false
                minifyEnabled true
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
    }
    

    BuildVariant

    ProductFlavor与BuildType组合,就成为BuildVariant。在前面多纬度Flavor的示例基础上,6个Flavor组合2个BuildType,总共就会有12种BuildVariant。

    每个Build Variant包含了一个ProductFlavor和一个BuildType。BuildType和ProductFlavor中某些配置是重叠的,组合成BuildVariant后,通常会按优先级处理(一般BuildType优先级更高),或做合并处理。

    例如两者都可以配置签名signingConfigs,合并成BuildVariant后,会优先取取BuildType中定义的;而对于配置项proguardFiles,则会采取合并处理。

    具体的合并逻辑,可以参考这个类中的实现
    com.android.builder.core.VariantConfiguration

    BuildConfig

    Android开发常用到BuildConfig类,这个类可在编译时生成,用于在代码中获取一些编译相关的参数,包括是否可以Debug、当前BuildType和Flavor名字、VersionCode和VersionName等,例如常会用BuildConfig.DEBUG判断是否输出Log信息。

    BuildType配置中提供了一个buildConfigField方法,可以往BuildConfig中添加自定义字段。

    int xxLibraryVersion = 192
    android {
        buildTypes {
            debug {
                buildConfigField "int", "XX_LIBRARY_VERSION", xxLibraryVersion
            }
            release {
                buildConfigField "int", "XX_LIBRARY_VERSION", xxLibraryVersion
            }
        }
    }
    dependencies {
        compile "com.xxx:xx:1.0.${xxLibraryVersion}"
    }
    
    public final class BuildConfig {
      public static final boolean DEBUG = Boolean.parseBoolean("true");
      public static final String BUILD_TYPE = "debug";
      // Fields from build type: debug
      public static final int XX_LIBRARY_VERSION = 192;
    }
    
    private void showLibraryInfo() {
        String msg = "xx library version is " + BuildConfig.XX_LIBRARY_VERSION;
        Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
    }
    

    Configurations

    在Gradle中,一个Project可以有多个Configuration,每个Configuration有不同的依赖配置。

    例如在dependencies中,经常用到compile xxx,这里的compile就是一个Configuration。一些常用的Configuration例如:

    • compile:最常用,参与编译并打包到APK中
    • testCompile:用于单元测试
    • androidTestCompile:用于Android自动化测试
    • provided:参与编译但不打包到APK中,类似eclipse中的external-libs
    • apk:打包到APK中但不参与编译,不能在代码中调用

    考虑到BuildType和ProductFlavor,又会和上述Configuration组合成新的Configuration,例如:

    • compile
    • debugCompile
    • myflavorCompile
    • myflavorDebugCompile
    • testCompile
    • testDebugCompile
    • testMyflavorCompile
    • testMyflavorDebugCompile

    在运行gradle dependencies时,也会分别显示每个Configuration对应的依赖树,如下(省略了部分输出)。

    ./gradlew :app:dependencies
    
    :app:dependencies
    
    ------------------------------------------------------------
    Project :app
    ------------------------------------------------------------
    
    androidJacocoAgent - The Jacoco agent to use to get coverage data.
    \--- org.jacoco:org.jacoco.agent:0.7.5.201505241946
    
    androidJacocoAnt - The Jacoco ant tasks to use to get execute Gradle tasks.
    \--- org.jacoco:org.jacoco.ant:0.7.5.201505241946
         +--- org.jacoco:org.jacoco.core:0.7.5.201505241946
         |    \--- org.ow2.asm:asm-debug-all:5.0.1
         +--- org.jacoco:org.jacoco.report:0.7.5.201505241946
         |    +--- org.jacoco:org.jacoco.core:0.7.5.201505241946 (*)
         |    \--- org.ow2.asm:asm-debug-all:5.0.1
         \--- org.jacoco:org.jacoco.agent:0.7.5.201505241946
    
    androidTestAnnotationProcessor - Classpath for the annotation processor for 'androidTest'.
    No dependencies
    
    androidTestApk - Classpath packaged with the compiled 'androidTest' classes.
    No dependencies
    
    androidTestCompile - Classpath for compiling the androidTest sources.
    No dependencies
    
    androidTestJackPlugin - Classpath for the 'androidTest' Jack plugins.
    No dependencies
    
    androidTestProvided - Classpath for only compiling the androidTest sources.
    No dependencies
    
    androidTestWearApp - Link to a wear app to embed for object 'androidTest'.
    No dependencies
    
    annotationProcessor - Classpath for the annotation processor for 'main'.
    No dependencies
    
    apk - Classpath packaged with the compiled 'main' classes.
    No dependencies
    
    archives - Configuration for archive artifacts.
    No dependencies
    
    compile - Classpath for compiling the main sources.
    +--- com.android.support:appcompat-v7:24.0.0
    |    +--- com.android.support:support-v4:24.0.0
    |    |    \--- com.android.support:support-annotations:24.0.0
    |    +--- com.android.support:support-vector-drawable:24.0.0
    |    |    \--- com.android.support:support-v4:24.0.0 (*)
    |    \--- com.android.support:animated-vector-drawable:24.0.0
    |         \--- com.android.support:support-vector-drawable:24.0.0 (*)
    \--- com.android.support.constraint:constraint-layout:1.0.2
         \--- com.android.support.constraint:constraint-layout-solver:1.0.2
    
    debugAnnotationProcessor - Classpath for the annotation processor for 'debug'.
    No dependencies
    
    debugApk - Classpath packaged with the compiled 'debug' classes.
    No dependencies
    
    debugCompile - Classpath for compiling the debug sources.
    No dependencies
    
    debugJackPlugin - Classpath for the 'debug' Jack plugins.
    No dependencies
    
    debugProvided - Classpath for only compiling the debug sources.
    No dependencies
    
    debugWearApp - Link to a wear app to embed for object 'debug'.
    No dependencies
    
    default - Configuration for default artifacts.
    No dependencies
    
    default-mapping - Configuration for default mapping artifacts.
    No dependencies
    
    default-metadata - Metadata for the produced APKs.
    No dependencies
    
    jackPlugin - Classpath for the 'main' Jack plugins.
    No dependencies
    
    provided - Classpath for only compiling the main sources.
    No dependencies
    
    ...
    

    SourceSet

    Gradle中使用SourceSet管理Java源码;Android定义了自己的SourceSet,其用法和Gradle类似。

    Gradle的SourceSet官方文档:
    https://docs.gradle.org/current/dsl/org.gradle.api.tasks.SourceSet.html

    Android的SourceSet官方文档:
    http://google.github.io/android-gradle-dsl/current/com.android.build.gradle.api.AndroidSourceSet.html

    默认的SourceSet即main,根目录位于src/main,其中又包括多个子目录,例如:

    • src/main/java,Java源码
    • src/main/resources,Java资源文件
    • src/main/res,Android资源文件
    • src/main/assets,Android assets文件

    ProductFlavor、BuildType、BuildVariant、test/androidTest,也会按照一定的形式组合产生SourceSet。

    可以配置某个SourceSet的根目录,或者指定具体的子目录(支持多个目录),如下:

    android {
        sourceSets {
            myflavor {
                res.srcDirs = ['src/main/res', 'src/main/res2']
            }
            debug.setRoot('src/main')
        }
    }
    

    使用Gradle的sourceSet可以查看项目中所有的SourceSet。

    $ ./gradlew :app:sourceSets
    :app:sourceSets
    
    ------------------------------------------------------------
    Project :app
    ------------------------------------------------------------
    
    androidTest
    -----------
    Compile configuration: androidTestCompile
    build.gradle name: android.sourceSets.androidTest
    Java sources: [app/src/androidTest/java]
    Manifest file: app/src/androidTest/AndroidManifest.xml
    Android resources: [app/src/androidTest/res]
    Assets: [app/src/androidTest/assets]
    AIDL sources: [app/src/androidTest/aidl]
    RenderScript sources: [app/src/androidTest/rs]
    JNI sources: [app/src/androidTest/jni]
    JNI libraries: [app/src/androidTest/jniLibs]
    Java-style resources: [app/src/androidTest/resources]
    
    androidTestMyflavor
    -------------------
    Compile configuration: androidTestMyflavorCompile
    build.gradle name: android.sourceSets.androidTestMyflavor
    Java sources: [app/src/androidTestMyflavor/java]
    Manifest file: app/src/androidTestMyflavor/AndroidManifest.xml
    Android resources: [app/src/androidTestMyflavor/res]
    Assets: [app/src/androidTestMyflavor/assets]
    AIDL sources: [app/src/androidTestMyflavor/aidl]
    RenderScript sources: [app/src/androidTestMyflavor/rs]
    JNI sources: [app/src/androidTestMyflavor/jni]
    JNI libraries: [app/src/androidTestMyflavor/jniLibs]
    Java-style resources: [app/src/androidTestMyflavor/resources]
    
    debug
    -----
    Compile configuration: debugCompile
    build.gradle name: android.sourceSets.debug
    Java sources: [app/src/debug/java]
    Manifest file: app/src/debug/AndroidManifest.xml
    Android resources: [app/src/debug/res]
    Assets: [app/src/debug/assets]
    AIDL sources: [app/src/debug/aidl]
    RenderScript sources: [app/src/debug/rs]
    JNI sources: [app/src/debug/jni]
    JNI libraries: [app/src/debug/jniLibs]
    Java-style resources: [app/src/debug/resources]
    
    main
    ----
    Compile configuration: compile
    build.gradle name: android.sourceSets.main
    Java sources: [app/src/main/java]
    Manifest file: app/src/main/AndroidManifest.xml
    Android resources: [app/src/main/res]
    Assets: [app/src/main/assets]
    AIDL sources: [app/src/main/aidl]
    RenderScript sources: [app/src/main/rs]
    JNI sources: [app/src/main/jni]
    JNI libraries: [app/src/main/jniLibs]
    Java-style resources: [app/src/main/resources]
    
    myflavor
    --------
    Compile configuration: myflavorCompile
    build.gradle name: android.sourceSets.myflavor
    Java sources: [app/src/myflavor/java]
    Manifest file: app/src/myflavor/AndroidManifest.xml
    Android resources: [app/src/myflavor/res]
    Assets: [app/src/myflavor/assets]
    AIDL sources: [app/src/myflavor/aidl]
    RenderScript sources: [app/src/myflavor/rs]
    JNI sources: [app/src/myflavor/jni]
    JNI libraries: [app/src/myflavor/jniLibs]
    Java-style resources: [app/src/myflavor/resources]
    
    myflavorDebug
    -------------
    Compile configuration: myflavorDebugCompile
    build.gradle name: android.sourceSets.myflavorDebug
    Java sources: [app/src/myflavorDebug/java]
    Manifest file: app/src/myflavorDebug/AndroidManifest.xml
    Android resources: [app/src/myflavorDebug/res]
    Assets: [app/src/myflavorDebug/assets]
    AIDL sources: [app/src/myflavorDebug/aidl]
    RenderScript sources: [app/src/myflavorDebug/rs]
    JNI sources: [app/src/myflavorDebug/jni]
    JNI libraries: [app/src/myflavorDebug/jniLibs]
    Java-style resources: [app/src/myflavorDebug/resources]
    
    myflavorRelease
    ---------------
    Compile configuration: myflavorReleaseCompile
    build.gradle name: android.sourceSets.myflavorRelease
    Java sources: [app/src/myflavorRelease/java]
    Manifest file: app/src/myflavorRelease/AndroidManifest.xml
    Android resources: [app/src/myflavorRelease/res]
    Assets: [app/src/myflavorRelease/assets]
    AIDL sources: [app/src/myflavorRelease/aidl]
    RenderScript sources: [app/src/myflavorRelease/rs]
    JNI sources: [app/src/myflavorRelease/jni]
    JNI libraries: [app/src/myflavorRelease/jniLibs]
    Java-style resources: [app/src/myflavorRelease/resources]
    
    release
    -------
    Compile configuration: releaseCompile
    build.gradle name: android.sourceSets.release
    Java sources: [app/src/release/java]
    Manifest file: app/src/release/AndroidManifest.xml
    Android resources: [app/src/release/res]
    Assets: [app/src/release/assets]
    AIDL sources: [app/src/release/aidl]
    RenderScript sources: [app/src/release/rs]
    JNI sources: [app/src/release/jni]
    JNI libraries: [app/src/release/jniLibs]
    Java-style resources: [app/src/release/resources]
    
    test
    ----
    Compile configuration: testCompile
    build.gradle name: android.sourceSets.test
    Java sources: [app/src/test/java]
    Java-style resources: [app/src/test/resources]
    
    testDebug
    ---------
    Compile configuration: testDebugCompile
    build.gradle name: android.sourceSets.testDebug
    Java sources: [app/src/testDebug/java]
    Java-style resources: [app/src/testDebug/resources]
    
    testMyflavor
    ------------
    Compile configuration: testMyflavorCompile
    build.gradle name: android.sourceSets.testMyflavor
    Java sources: [app/src/testMyflavor/java]
    Java-style resources: [app/src/testMyflavor/resources]
    
    testMyflavorDebug
    -----------------
    Compile configuration: testMyflavorDebugCompile
    build.gradle name: android.sourceSets.testMyflavorDebug
    Java sources: [app/src/testMyflavorDebug/java]
    Java-style resources: [app/src/testMyflavorDebug/resources]
    
    testMyflavorRelease
    -------------------
    Compile configuration: testMyflavorReleaseCompile
    build.gradle name: android.sourceSets.testMyflavorRelease
    Java sources: [app/src/testMyflavorRelease/java]
    Java-style resources: [app/src/testMyflavorRelease/resources]
    
    testRelease
    -----------
    Compile configuration: testReleaseCompile
    build.gradle name: android.sourceSets.testRelease
    Java sources: [app/src/testRelease/java]
    Java-style resources: [app/src/testRelease/resources]
    
    
    BUILD SUCCESSFUL
    
    Total time: 1.041 secs
    

    SourceSet的合并、Manifest合并

    对于某个具体的编译任务中某一类源文件,会根据一定的优先级与合并规则,对多个SourceSet中的同类源文件进行合并得到。

    一般情况下,优先级从高到底分别是:

    • BuildVariant(src/armFreeappDebug)
    • BuildType(src/debug)
    • MultiFlavor(src/armFreeapp)
    • 每个单独的Flavor(src/arm, src/freeapp)
    • sourceSet.main(src/main)
    • 依赖中的对应文件(JAR、AAR或SubProject中解析出来的源文件)

    对于Java类、drawable目录下的图片资源文件、layout等,合并措施一般就是同名文件直接覆盖。

    对于values目录下的标签类型资源,合并时会以每个标签为最小单元进行覆盖。

    <!-- 多个SourceSet都定义了同名style标签,则高优先级会直接覆盖低优先级 -->
    <!-- src/debug/res/values/xxx.xml  高优先级 -->
    <style name="txt_main">
        <item name="android:textSize">12sp</item>
    </style>
    
    <!-- src/main/res/values/yyy.xml  低优先级 -->
    <style name="txt_main">
        <item name="android:textSize">14sp</item>
        <item name="android:textColor">@android:color/white</item>
    </style>
    
    <!-- 合并后 -->
    <style name="txt_main">
        <item name="android:textSize">12sp</item>
    </style>
    

    而Manifest文件的合并规则更复杂一些。具体可参考官方文档:

    https://developer.android.com/studio/build/manifest-merge.html

    Android Gradle Task

    Android Gradle环境下,有下面几个常见的Task。

    • assemble:Gradle内建的编译任务(生成APK / JAR / AAR)
    • test:Gradle内建的测试任务
    • lint:Android定义的Lint检查任务
    • check:Gradle内建的检查任务,依赖lint、test
    • build:Gradle内建的Build任务,依赖assemble、check

    结合ProductFlavor、BuildType、BuildVariant,又会组合成很多Task。

    这些Task的依赖关系示例如下:

    app:build
            app:check
                    app:lint
                    app:test
                            app:testMyflavor2DebugUnitTest
                            app:testMyflavor2ReleaseUnitTest
                            app:testMyflavor1DebugUnitTest
                            app:testMyflavor1ReleaseUnitTest
            app:assemble
                    app:assembleDebug
                            app:assembleMyflavor2Debug
                            app:assembleMyflavor1Debug
                    app:assembleRelease
                            app:assembleMyflavor1Release
                            app:assembleMyflavor2Release
    

    Android Studio/IDEA相关

    在Android Studio/IDEA中开发时,会在Build Variants窗口选择指定的Build参数,例如myflavor1Debug。

    Sync Project With Gradle Files

    当修改了gradle文件等情况,会提示:

    Gradle files have changed since last project sync. A project sync may be necessary for the IDE to work properly.

    此时点击提示栏中的Sync,会触发Gradle同步操作。刚打开工程,或者手动选择菜单Tools-Android-Sync Project With Gradle Files或工具栏中的同步按钮,也会触发同步操作。

    在同步过程中,Gradle会执行很多任务,包括解析并下载所有依赖项,解压AAR、合并SourceSet、生成BuildConfig、R文件(结果会输出到build目录)等,这样Android Studio就能加载所有引用的class、jar文件,对源码进行语法解析,从而代码也可以正常的跳转了。

    通过GradleConsole窗口,可以看到同步过程中Gradle所执行的Task,其中最主要的是generateMyflavor1DebugSources,即生成源码的过程,依赖了prepareMyflavor1DebugDependencies、generateMyflavor1DebugBuildConfig、generateMyflavor1DebugResValues等Task。

    :app:preBuild UP-TO-DATE
    :app:preMyflavor1DebugBuild UP-TO-DATE
    :app:checkMyflavor1DebugManifest
    :app:preMyflavor1ReleaseBuild UP-TO-DATE
    :app:preMyflavor2DebugBuild UP-TO-DATE
    :app:preMyflavor2ReleaseBuild UP-TO-DATE
    :app:prepareComAndroidSupportAnimatedVectorDrawable2400Library
    :app:prepareComAndroidSupportAppcompatV72400Library
    :app:prepareComAndroidSupportConstraintConstraintLayout102Library
    :app:prepareComAndroidSupportSupportV42400Library
    :app:prepareComAndroidSupportSupportVectorDrawable2400Library
    :app:prepareComFacebookFrescoDrawee0100Library
    :app:prepareComFacebookFrescoFbcore0100Library
    :app:prepareComFacebookFrescoFresco0100Library
    :app:prepareComFacebookFrescoImagepipeline0100Library
    :app:prepareComFacebookFrescoImagepipelineBase0100Library
    :app:prepareMyflavor1DebugDependencies
    :app:compileMyflavor1DebugAidl
    :app:compileMyflavor1DebugRenderscript
    :app:generateMyflavor1DebugBuildConfig
    :app:generateMyflavor1DebugResValues
    :app:generateMyflavor1DebugResources
    :app:mergeMyflavor1DebugResources
    :app:processMyflavor1DebugManifest
    :app:processMyflavor1DebugResources
    :app:generateMyflavor1DebugSources
    :app:preMyflavor1DebugAndroidTestBuild UP-TO-DATE
    :app:prepareMyflavor1DebugAndroidTestDependencies
    :app:compileMyflavor1DebugAndroidTestAidl
    :app:processMyflavor1DebugAndroidTestManifest
    :app:compileMyflavor1DebugAndroidTestRenderscript
    :app:generateMyflavor1DebugAndroidTestBuildConfig
    :app:generateMyflavor1DebugAndroidTestResValues
    :app:generateMyflavor1DebugAndroidTestResources
    :app:mergeMyflavor1DebugAndroidTestResources
    :app:processMyflavor1DebugAndroidTestResources
    :app:generateMyflavor1DebugAndroidTestSources
    :app:mockableAndroidJar UP-TO-DATE
    :app:preMyflavor1DebugUnitTestBuild UP-TO-DATE
    :app:prepareMyflavor1DebugUnitTestDependencies
    
    BUILD SUCCESSFUL
    
    Total time: 6.425 secs
    

    Run

    点击三角形箭头时,除了执行assembleMyflavor1Debug,还会执行install(将APK安装至设备)等Task。

    在Android Studio的Run/Debug Configuration窗口中,还可以指定点击三角箭头时要执行的Gradle Task。例如可以添加一个clean操作,每次编译前先用clean清理build目录。

    AAR多版本发布

    Android开发经常会用到AAR,有时候希望AAR能支持发布多个版本,并在不同的情况下依赖不同版本(包括不同的BuildType和ProductFlavor)。例如主工程依赖xxLibrary,希望Debug版本APK依赖Debug版本的AAR,而Release版本APK依赖Release版本的AAR。

    在Android中依赖SubProject或AAR时,如果没有特殊配置,AAR的发布和模块依赖默认均为Release版本。

    实际尝试主工程依赖子工程,子工程中读取BuildConfig.DEBUG的值始终是false,修改Android Studio中子模块的BuildVariant配置也没有效果。

    dependencies {
        compile project(':xxx_library')
        compile 'com.xxx:xxx:1.0.5@aar' {
            transitive = true
        }
    }
    

    可用如下方式配置子模块或者独立AAR工程发布所有版本:

    apply plugin: 'com.android.library'
    
    android {
        // 发布非默认版本
        publishNonDefault true
        // 指定默认版本,发布AAR到Maven时会从默认版本生成POM依赖配置。
        // 不指定会导致POM无法正确生成,从而依赖不能传递。
        defaultPublishConfig "falvorARelease"
    
        productFlavors {
            flavorA { }
            flavorB { }
        }
    }
    

    用下面的方式依赖子模块或已经发布的AAR:

    dependencies {
    
        // Debug、Release版本APK,分别依赖Debug、Release版本子模块
        debugCompile project(path: ':xxx', configuration: 'flavorADebug')
        releaseCompile project(path: ':xxx', configuration: 'flavorARelease')
    
        // 指定依赖aar版本,并设置transitive为true
        debugCompile('com.xxx:library:1.0.5:flavorADebug@aar') {
            transitive = true
        }
        releaseCompile('com.xxx:library:1.0.5:flavorARelease@aar') {
            transitive = true
        }
    }
    

    本文首发自我的个人博客 http://www.paincker.com/android-gradle-basics

    相关文章

      网友评论

      • 英雄是孤独的_60c6:你好,请问为啥我按你的流程编译源码后,没有对应的libjingle_peerconnection_java.jar包

      本文标题:Android Gradle配置快速入门

      本文链接:https://www.haomeiwen.com/subject/netcxftx.html