运行环境
系统: mac OS
IDE: Android Studio 2.3
Gradle: 3.3
一. 问题
library module的gradle配置里面有这样两个默认配置:
android {
defaultPublishConfig "release"
publishNonDefault false
}
有图为证:
这个配置的作用是: 无论主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关系如下图所示:
因为上述默认配置的作用, 无论你的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
}
这个解决方法的优点:
- 灵活自由. 你想让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啦
具体思路:
- 在主module的build.gradle中, 从task名称中解析出buildType, 然后设置给library
- 在library的build.gradle中获取主module设置过来的buildType, 并重新指定defaultPublishConfig
具体步骤如下(具体可参考github中的app-linkage和library-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)
今天在公司项目中使用上述方案时发现有问题, 具体如下:
- 错误:
在项目根目录执行./gradlew clean :myapp:assembleDebug
时出现下面的错误:
当然直接执行./gradlew clean
可能也会出现上面的错. - 解决:
很不幸的告诉你上面的解决方案, 暂时不支持组合命令 (一次执行多个task). - 如果你执行像
./gradlew clean :app:assembleDebug
这样的命令, 那么请你按两步执行, 如下:
./gradlew clean
./gradlew :app:assembleDebug
- 为了保证执行像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)的优化配置