如何让library的buildType类型跟app的buildType类型一致(自由定义library的buildType) ??

运行环境
系统: mac OS
IDE: Android Studio 2.3
Gradle: 3.3


一. 问题

library module的gradle配置里面有这样两个默认配置:

android {
    defaultPublishConfig "release"
    publishNonDefault false
}

有图为证:

.png

这个配置的作用是: 无论主module以什么build type来构建, 我 (library) 都将以release模式来构建 !!
一般我们不会去更改这个配置, 也没有必要去修改.
但是如 Android中使用BuildConfig.DEBUG必须知道的内幕 这篇文章中所说, 你把一个工具类写在library中, 而且这个工具类依赖于buildType (例如, 工具类依赖于BuildConfig.DEBUG --- 这个常量是依赖于buildType的), 这时如果不根据主module的buildType来设置library module的buildType, 就会出现这样一种情况, 你打的debug包将无法使用library库中的debug功能 !!!
为何如此, 我们就来分析一下. 主module和library module的build type关系如下图所示:
主module和library module的build type关系.png

因为上述默认配置的作用, 无论你的app打什么包, 它所依赖的library都将以release模式构建, 这就导致app打debug包时, library库的buildType却是 release.
这个问题, 在 Android中使用BuildConfig.DEBUG必须知道的内幕 这篇文章中已经解决, 即在主module中根据buildType来依赖library. 但是又有人提出了新的问题: 如果library有多个productFlavor, 那我主module对library的依赖该如何写?

二. 解决方案

productFlavor可能非常多, 而buildType基本上就是debug或release, 因此我们还是让主module从buildType这个纬度来依赖library.

解铃还须系铃人, 既然是gradle默认配置导致的"问题", 那就从它入手吧 (默认配置正好是跟buildType相关的)!

从默认配置入手有两个思路:
a. publishNonDefault配置的作用: 是否关闭默认发布配置 (true关闭, false开启)
因此最先想到的是: 关闭默认发布配置, 即将publishNonDefault设为true (言外之意, library的buildType会和主module的buildType保持一致了).
经过尝试, 然并卵!!

b. 是否可把library的defaultPublishConfig设置为主module的buildType类型?

从这条思路出发, 几经折腾, 找到最终解决方案: **根据用户需求, 指定library的buildType (从命令行获取library所需的buildType类型) !! **

注意: 下面是重点

具体步骤如下 (具体可以参考app/library这两个module的build.gradle配置):
**0x1. 给apk构建命令添加一个参数 (bt, 即buildType), 即library所需的buildType . **
编译或者安装命令, 有下列组合 (如果定义类productFlavor, 会有更多组合, 自己组合即可):

./gradlew -Pbt=0 :app:assembleDebug      //打debug包, library用debug模式打包
./gradlew -Pbt=1 :app:assembleDebug      //打debug包, library用release模式打包
./gradlew -Pbt=0 :app:assembleRelease    //打release包, library用debug模式打包
./gradlew -Pbt=1 :app:assembleRelease    //打release包, library用release模式打包
./gradlew -Pbt=0 :app:installDebug       //安装debug包, library用debug模式打包
./gradlew -Pbt=1 :app:installDebug       //安装debug包, library用release模式打包
./gradlew -Pbt=0 :app:installRelease     //安装release包, library用debug模式打包
./gradlew -Pbt=1 :app:installRelease     //安装release包, library用release模式打包

**0x2. 在主module的构建脚本build.gradle中解析命令行传入的buildType参数, 并传递给library. **
关键代码如下:

//1. 获取命令行传入的buildType
String getBuildType() {
    //为了简化输入(debug/release) : bt=0 表示buildType为debug; bt=1 表示buildType为release
    String buildTypeI =  hasProperty("bt") ? "$bt" : "0"  //如果命令行不传bt参数, library默认使用debug模式发布
    return buildTypeI.equals("1") ? "release" : "debug"
}

dependencies {
    //其他依赖省略 ...

    //2. 将命令行所指定的buildType传入到library module中
    compile project(':library', { pj ->
        pj.ext.buildType = getBuildType()
    })
}

**0x3. 在library的构建脚本build.gradle中解析主module传过来的buildType 并 重新指定 defaultPublishConfig 配置 **
关键代码如下:

apply plugin: 'com.android.library'

//1. 获取主module传过来的buildType
def currentBuildType = "${ext.buildType}"

android {
    //其他配置省略 ...

    //2. 修改默认发布类型
    defaultPublishConfig currentBuildType
}

这个解决方法的优点:

  1. 灵活自由. 你想让library用哪种方式发布都可以, 只要改变传参就可以了, 没有任何限制. 你的debug包可以用library中的release功能, 而你的release包也可以用library的debug功能 !!

源码在此Gradle-Explore, 欢迎Start (♥◠‿◠)ノ !!


@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

更新于(2017-04-05)

如果要library module和主module的buildType一致, 而又嫌输入额外参数麻烦, 那么可以直接根据task的名称(assembleDebug/assembleRelease ...) 来指定library的buildType, 因为task名称里面就包含了buildType,
如, assembleDebug/assembleRelease, installDebug/installRelease, 后面的debug/release就是buildType啦

具体思路:

  1. 在主module的build.gradle中, 从task名称中解析出buildType, 然后设置给library
  1. 在library的build.gradle中获取主module设置过来的buildType, 并重新指定defaultPublishConfig

具体步骤如下(具体可参考github中的app-linkagelibrary-linkage这两个module的build.gradle配置):

0x01. 打包命令不用加额为参数, 原来是什么现在还是什么, 如./gralew :app:assembleDebug
0x02. 在主module的build.gradle中添加下面关键代码:

//1. 从命令行中解析出buildType
def currentBuildType = "release" //library默认使用buildType为release
gradle.startParameter.taskNames.each({
    String taskNameL = it.toLowerCase();
    if(taskNameL.contains("assemble") || taskNameL.contains("install")) {
        if(taskNameL.contains("debug")) {
            currentBuildType = "debug"
            return;
        } else if(taskNameL.contains("release")) {
            currentBuildType = "release"
            return;
        }
    }
})

dependencies {
    //其他依赖省略...

    compile project(':library-linkage', { pj ->
        //2. 将解析出的buildType设置给library
        pj.ext.buildType = currentBuildType
    })
}

0x03. library module的build.gradle配置和之前 (用命令行额外参数bt指定module的buildType) 一样, 如下:

apply plugin: 'com.android.library'


//1. 获取主module给library设置的buildType
def currentBuildType = "${ext.buildType}"

android {
    //其他配置省略...

    //2. 重新指定defaultPublishConfig
    defaultPublishConfig currentBuildType
}

更新完毕 !


@@@@@@@@@@@@@@@@@@

更新于(2017-04-028)

今天在公司项目中使用上述方案时发现有问题, 具体如下:

  1. 错误:
    在项目根目录执行./gradlew clean :myapp:assembleDebug时出现下面的错误:
    C81470B4-FF8B-4D8C-8E81-960AD56ECF0F.png

    当然直接执行./gradlew clean可能也会出现上面的错.
  2. 解决:
    很不幸的告诉你上面的解决方案, 暂时不支持组合命令 (一次执行多个task).
  3. 如果你执行像
    ./gradlew clean :app:assembleDebug 这样的命令, 那么请你按两步执行, 如下:
./gradlew clean
./gradlew :app:assembleDebug
  1. 为了保证执行像clean这样的task时不出现上面的错误, android library module的build.gradle中获取buidType的语句需要更改成这样:
    def currentBuildType = extensions.extraProperties.has("buildType") ? "${ext.buildType}" : "release"

References:
如果你想把一些工具类定义在library中, 且这些工具类依赖于buildType (即根据构建方式 debug或release 做不同处理), 还可以参考:
Android中使用BuildConfig.DEBUG必须知道的内幕
Android: 使用BuildConfig.DEBUG优化你的Log输出 & 开启混淆(proguard)的优化配置

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

推荐阅读更多精彩内容