Gradle

一、多工程配置

Gradle工程可以通过多工程配置来依赖其他的Gradle工程。
多工程配置通常把所有的工程作为"根目录的子文件夹";
比如下面的工程:

MyProject/
  app/
  libraries/
     lib1/
     lib2/

我们可以识别这三个工程。Gradle会通过如下名字引用它们:

:app
:libraries:lib1
:libraries:lib2

每个工程都有自己的build.gradle文件来定义如何构建自己。
此外,工程的根目录中有个settings.gradle的文件,会定义所有的工程;
文件目录结构如下:

MyProject/
 settings.gradle
 app/
    build.gradle
 libraries/
    lib1/
       build.gradle
    lib2/
       build.gradle

settings.gradle文件中的配置如下:

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

这里定义了哪些文件是一个Gradle工程;
:app工程也可能会依赖一些库工程,可以通过如下脚本声明依赖:

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

二、库工程
  • 普通工程和库工程的不同:
    库工程的main输出的是一个.aar包,它由编译后的代码(比如jar文件或者.so文件)以及资源文件(manifest,res,assets)组成。 库工程也可以生成一个测试apk,可以独立于应用进行测试。
    它有相同的引导任务( assembleDebug , assembleRelease ),所以他和一般的工程没有什么不同。
    其余的,基本上都和应用一样了。他们都有build types和product flavors,可以生成多个版本的aar。 注意 Build Type 大部分配置并不适用于库工程。不过你可以依据库工程是被其他工程依赖还是测试,然后通过自定义库工程 sourceSet 改变它的内容。
  • 库工程的发布

默认情况下库工程只能发布release版本。这个版本用于所有工程的引用,和工程要构建什么样的版本无关--这是属于Gradle的限制;

三、根目录的build.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.
//buildscripe{...}这部分用来配置驱动构建的代码
//这部分配置只会影响构建过程,和工程没有关系;工程会定义它自己的仓库和相关依赖
buildscript {
    //配置使用什么仓库
    repositories {
        //指定仓库URL快捷方式
        jcenter()
    }
    //配置 依赖什么插件
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'

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

allprojects {
    repositories {
        jcenter()
    }
}

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

/**
 * 设置全局参数
 * 可以在app/build.gradle中使用:
 * compileSdkVersion rootProject.ext.compileSdkVersion
 * buildToolsVersion rootProject.ext.buildToolsVersion
 */
ext {
    compileSdkVersion = 26
    buildToolsVersion = "26.0.2"
}
五、app下面的build.gradle
//配置应用android插件;
//备注:只应用android插件就好了,不要同时应用java插件,因为这会导致构建错误
apply plugin: 'com.android.application'

import com.android.build.OutputFile

//可以从文件中读取版本名字或者使用一些其他的自定义逻辑
def computeVersionName(){

    "1.0.2"//不用写return  默认最后一行就是返回值
}

//配置了android构建需要的所有参数,默认情况下只有编译sdk的版本(compileSDKVersion)、构建工具版本(buildToolsVersion)是必须的;
//android 元素里的 defaultConfig 负责定义所有的配置。
android {
    //使用全局配置--配置见project/build.gradle
    compileSdkVersion rootProject.ext.compileSdkVersion
    buildToolsVersion rootProject.ext.buildToolsVersion
    defaultConfig {
        applicationId "com.zcbl.client.zcblsdk"
        minSdkVersion 23
        targetSdkVersion 26
        versionCode 1
        versionName computeVersionName()
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

        ndk{
            //生成.so的名字
            moduleName "hello"

        }

//        multiDexEnabled true
    }

    /**
     * 这前用上面multiDexEnabled true时,
     * 突然在5.0以下的手机上跑不起来,
     * 改成下面这种写法就可以了。
     */
    dexOptions {
        jumboMode true
    }

    buildTypes {
        release {
            minifyEnabled false
            //有两个默认的规则文件
            //1.proguard-android.txt
            //2.proguard-android-optimize.txt
            //它们都位于SDK中,使用getDefaultProguardFile()方法可以返回文件的全路径。二者除了是否开启优化之外,其他功能全相同;
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            // 构建类型是否应该生成可调试的apk
//            debuggable true
        }

        debug {
            //配置了默认debug的构建类型:设置包名以.debug为后缀,这样和release的包名不一致了,就能在同一个设备上\
            //                        同时安装debug和release两个版本的APK
            applicationIdSuffix ".debug"
            //构建类型是否配置为使用可调试的本机代码生成APK
//            jniDebuggable true
            //注意:使用此配置,需要注释点res/strings/中的app_name ,用来动态配置不同app的名字
//            resValue('string','app_name','测试版')

        }

        //创建一个buildTypes很简单,只需要在buildTypes容器中添加一个元素,然后调用initWith()或者使用一个闭包配置它;
        //initWith所传的参数是为了配置作为哪个(release或者debug)的副本,也就说打出来的包用什么证书签名;
        //如果不传参数,将会打出一个没有被签名的apk文件
        jnidebug.initWith(buildTypes.debug)

        jnidebug {
            applicationIdSuffix ".jnidebug"
//            packageNameSuffix ".jnidebug"//decorated
            jniDebuggable true
            versionNameSuffix ".debug"
//            signingConfig
//            proguardFile
//            proguardFiles
//            minifyEnabled
//            zipAlignEnabled
//            debuggable
//            jniDebuggable
//            renderscriptDebuggable
//            renderscriptOptimLevel
//            manifestPlaceholders = [PGY_PGYER_APPID:"********"]
//            buildConfigField('String','API_URL','\"http://www.baidu.com\"')
        }

    }



    //通常情况下,Build Type 配置会覆盖其他配置,比如,Build Type 的 packageNameSuffix 会追加到 Product Flavor 的 packageName 之后。

    //也有一些情况是在 Build Type 和 Product Flavor 中都可以设置,在这种情况下,视情况而定。

    //比如, signingConfig 就是这么一个属性。 通过设置 android.buildTypes.release.signingConfig ,可以为所
    // 有的release包共享相同的SigningConfig,也可以单独通过设置android.productFlavors.*.signingConfig为每
    // 一个release包指定他们自己的 SigningConfig 。



    /**
     * //指定两个维度:是否付费和发布的平台
     * flavorDimensions中定义的Dimensions排序很重要:这个排序决定了哪一个flavor中设置的属性覆盖哪一个,因为一个flavor中的
     *                  值(设置的属性)会被替换定义在底优先级的flavor中的值(属性);比如下面"发布平台(store)"中设置的versionName会
     *                  覆盖"是否付费(price)"中设置的versionName,也就是打出的包的versionName对应为:google,amazon,baidu;
     *                  但高优先级的会覆盖低优先级的资源--也就是res目录下的资源文件会遵循优先级覆盖的原则;
     */
    flavorDimensions "price","store"

    //android.productFlavors.*是ProductFlavor类型的,和android.defaultConfig对象具有相同的类型,这就意味着他们有相同的属性;
    //defalutConfig为所有的flavor提供了基本的配置,每一个falvor也都可以重新设置覆盖这些默认值;

    productFlavors{
        //favours的名字不能和Build Types 名字或者androidTest SourceSet冲突
        //每一个favours都可以通过一个闭包单独设置
        google{
            versionName 'google'
            dimension "store"
        }
        amazon{
            versionName 'amazon'
            dimension "store"
//            manifestPlaceholders = [PGY_PGYER_APPID:"********"]
            buildConfigField 'String','API_URL','\"API_URL_FLAVOR2\"'
            buildConfigField("boolean","LOG_DEBUG","false")
        }
        baidu{
            versionName 'baidu'
            dimension 'store'
        }
        free{
            versionName 'free'
            dimension 'price'
        }
        paid{
            versionName 'paid'
            dimension 'price'
        }

//        //下面的只有没有设置flavorDimensions时才能编译通过
//        tx{
//            versionName 'tx'
//        }
    }


    sourceSets {
//        main {
//            //修改项目目录:使用场景-->就是eclipse项目转Android studio项目,需要重新配置项目结构
//            //要替换默认的源文件夹的话,可以给 srcDirs 指定一个路径数组
//            manifest.srcFile 'AndroidManifest.xml'
//            java.srcDirs = ['src']
//            resources.srcDirs = ['src']
//            aidl.srcDirs = ['src']
//            renderscript.srcDirs = ['src']
//            res.srcDirs = ['res']
//            assets.srcDirs = ['assets']
//        }
    //不同产品不同的文件
//        falvor1 {
//            java.srcDirs = ['src/product/java']
//        }
//        falvor2 {
//            java.srcDirs = ['src/temp/java']
//        }
    }
//    //注意:srcDir 会添加指定的文件夹到现有的源文件夹列表中(Gradle文档没有提到这个,但是的确是这样的)

//当默认的工程结构不适用的时候,你可能需要配置它。根据Gradle文档说明,可以通过如下方式重新配置Java工程的 sourceSets:
//    sourceSets {
//        main {
//            java {
//                srcDir 'src/java' // 指定源码目录
//            }
//            resources {
//                srcDir 'src/resources'//资源目录
//            }
//            assets {
//                srcDir 'src/assets'
//            }
//        }
//    }

    /**
     * 主要用来配置打包时,来从哪里打包资源或者代码
     * 说白了 就是告诉编译器你从哪个文件下找出代码,打包进apk文件里
     */
//    sourceSets {
//        main() {
//            jniLibs.srcDirs = ['src/main/libs']
//            jni.srcDirs = []
//        }
//    }

    /**
     * 一般应该尽可能的建立一个单一的apk,这个apk可以支持所有的目标设备,但是这会导致一个apk包体积非常大;因为这个apk
     * 支持所有"屏幕密度"或"应用二进制接口"(ABI).
     * 减少apk体积的一种方法,就是创建支持特定屏幕密度或者abi的apk。
     *
     * Gradle可以使用splits来进行apk拆分:
     * 需要在splits{}中添加density{}或者abi{}闭包函数;
     * 参数说明:
     * enable:如果为true,Gradle会根据定义的屏幕密度或者abi来生成指定屏幕密度或者abi的apk包;默认为false;
     * exclude:用来排除应用不需要支持的屏幕密度或者abi,支持的类型一般用逗号分隔;
     * include:与exclude对应,只能与reset()结合使用才能指定支持的屏幕密度或者abi;支持的类型一般用逗号分隔;
     * reset():清除默认支持的屏幕密度或abi。注意:这个方法仅当与include元素组合使用时才能添加指定的屏幕密度或者abi;
     * 比如设置支持密度为ldpi和xxhdpi的设置如下:
     * splits{
     *     //density提供所需的屏幕密度和兼容的屏幕尺寸的列表
     *     density{
     *         reset()
     *         include "ldpi","xxhdpi"
     *     }
     * }
     *
     * compatibleScreens:指定兼容的屏幕尺寸,指定多个尺寸使用逗号分隔;这将在每个拆分的apk的manifest中注入匹配的<compatible-screens>节点;
     * 这个可选设置提供了在同一个build.gradle中管理屏幕密度和屏幕大小的方法;但是使用<compatible-screens>将限制应用程序使用的设配类型;
     * universalApk:这个是abi独有的一个配置;如果为true,Gradle将会生成包含所有abi的通用abi以及拆分的apk,通用apk中包含所有的abi代码和资源;
     *              默认值为false.
     *              密度APK分裂总是生成一个通用的APK,包含所有屏幕密度的代码和资源。
     */
//    splits{
//
////        density{
////            enable true
////            exclude "ldpi","xxhdpi","xxxhdpi"
////            compatibleScreens 'small','normal','large','xlarge'
////        }
//
//        abi{
//            enable true
//            reset()
//            include 'x86','armeabi-v7a'
//            universalApk true
//        }
//    }

    // map for the version code
//    project.ext.versionCodes = ['armeabi': 1, 'armeabi-v7a': 2, 'arm64-v8a': 3, 'mips': 5, 'mips64': 6, 'x86': 8, 'x86_64': 9]
//
//    // applicationVariants are e.g. debug, release
//    applicationVariants.all { variant ->
//        variant.outputs.each { output ->
//            // For each separate APK per architecture, set a unique version code as described here:
//            // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
////            def versionCodes = ["armeabi-v7a": 1, "x86": 2]
//
//            def abi = output.getFilter(OutputFile.ABI)
//            if (abi != null) {  // null for the universal-debug, universal-release variants
//                output.versionCodeOverride = project.ext.versionCodes.get(abi) * 100 + defaultConfig.versionCode
//            }
//        }
//    }

}

/**
 * 为了打包出不同versionCode值的配置
 * 下面的意思:将打出的x86的apk包的versionCode修改为301,将打出的armeabi-v7a的apk包的versionCode修改为:101
 * 同android节点下的配置效果一样
 */
project.ext.versionCodes = ['armeabi-v7a':1, mips:2, x86:3]
android.applicationVariants.all { variant ->
    // assign different version code for each output
    variant.outputs.each { output ->
        def abi = output.getFilter(OutputFile.ABI)
        if (null != abi) {
            output.versionCodeOverride = project.ext.versionCodes.get(abi) * 100 + android.defaultConfig.versionCode
        }

    }
}



//注:dependencies DSL元素是标准Gradle API的一部分,并不属于android的元素
dependencies {
    //compile 配置用来编译main application,它里面的一切都会被添加到编译的classpath中,并且也会被打包到最终的apk中
    //compile : main application
    //androidTestCompile: test application
    //debugCompile: debug Build Type
    //releaseCompile: release Build Type
    //因为要构建生成一个APK,必然会有相关联的Build Type,APK默认配置两个(或者更多)编译配置:compile和<buildtpe>Compile.
    //创建一个新的Build Type 的时候会自动创建一个基于它名字的编译配置;
    //当一个debug版本需要一个自定义库(比如报告崩溃),但是release版本不需要或者需要一个不同版本的库的时候,会显得非常有用;
    compile fileTree(include: ['*.jar'], dir: 'libs')
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:26.+'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:recyclerview-v7:26.0.0-alpha1'
    //配置依赖一个外部库jar包,可以在compile配置里添加一个依赖
//    compile files('libs/foo.jar')
    debugCompile 'com.android.support:recyclerview-v7:26.0.0-alpha1'
    //引用一个根目录下的库工程方式如下:
//    compile project(':libraries:lib1')

    //设置不同的产品引入不同的包
//    falvor1Compile 'com.android.support:recyclerview-v7:26.0.0-alpha1'
}

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

推荐阅读更多精彩内容

  • 结束了词汇的部分,今天开始就进入了拼写,作者提到了一些方法如眼部训练、联想记忆等方法通过训练你的大脑来消除拼写错误...
    泥巴叔叔阅读 226评论 0 1
  • 夜 吟 文|又人 这天,总是夜起幽凉,这夜,总是勾起悲怆。 无月之夜,与老庄骑车行于街道,...
    又人同学阅读 564评论 0 3
  • 创造1 就我的本心来讲,我想送人肯定是买当地的好。要是自己吃,学长的月饼口感和质量确实不错的。但是这东西自己吃,也...
    我和榕树阅读 242评论 0 0
  • 荷花拍的多了,再次面对,便失去拍摄的兴趣。既然了然无趣,索性换个主题。又是莲花绽开的时节,和麻豆约定了时间赏荷拍花...
    芥空阅读 210评论 2 2
  • 初遇时是在草长莺飞的春天,殊不知,那意外的一眼,陌生的悸动,从此便持续了几年。 楔子 坊间传言,在骊山深处有...
    远镇阅读 1,558评论 8 31