在 Gradle 中为 Android 中的库项目构建变体
Posted
技术标签:
【中文标题】在 Gradle 中为 Android 中的库项目构建变体【英文标题】:Build variants in Gradle for a Library Project in Android 【发布时间】:2013-07-01 08:50:03 【问题描述】:我正在尝试使用 Gradle 配置一个包含一些外部库的项目。使用 Gradle,我可以使用 Build Variants 为主应用程序设置不同的环境配置(在配置文件中包含一个类),以便我可以根据这些变量执行代码。
问题是我如何为图书馆项目做同样的事情?我为这个项目创建了这个库,我想为不同的场景设置不同的构建变体。
例如: 在库中,在调试模式下运行时,打印所有日志,以便我可以在开发时看到它们。在发布模式下不要。
文件结构:
src ----- > debug -> java -> config -> PlayerEnvConfig
main -> com.mypackagename -> etc...
release -> java -> config -> PlayerEnvConfig
调试中的代码: 包配置;
/**
* Environment configuration for Release
*/
public final class PlayerEnvConfig
public static final boolean USE_REPORTING = true;
public static final boolean USE_ANALYTICS = true;
public static final boolean USE_LOGGING = false;
public static final boolean USE_DEBUG_LOGGING = false;
public static final boolean USE_DEBUGING = false;
发布中的代码:
package config;
/**
* Environment configuration for Release
*/
public final class PlayerEnvConfig
public static final boolean USE_REPORTING = true;
public static final boolean USE_ANALYTICS = true;
public static final boolean USE_LOGGING = false;
public static final boolean USE_DEBUG_LOGGING = false;
public static final boolean USE_DEBUGING = false;
问题在于,对于主项目,我可以使用此构建类型为不同的场景配置不同的应用程序,但我怎样才能为库项目做同样的事情呢?
因为目前从我在http://tools.android.com/tech-docs/new-build-system/user-guide 中阅读的内容来看,该库仅在测试时使用调试模式。
有什么想法吗?
谢谢!
【问题讨论】:
【参考方案1】:这是来自google code issue 的@bifmadei 回答,对我有帮助:
过时 1: 尝试在依赖项目中设置这个
android
publishNonDefault true
...
Obsolete 2: 从 gradle 4.10.1 开始,publishNonDefault 默认为 true。因此,只需使用以下建议:
将它包含在使用它的项目中
dependencies
releaseCompile project(path: ':theotherproject', configuration: 'release')
debugCompile project(path: ':theotherproject', configuration: 'debug')
取自这里:https://code.google.com/p/android/issues/detail?id=66805
请注意,implementation
指令分隔 releaseCompile
和 debugCompile
已过时:https://***.com/a/44364851/3379437
更新:
上一步的方法仍然可以用于自定义构建配置:
implementation project(path: ':theotherproject', configuration: 'staging')
【讨论】:
这对我来说确实非常有效。请注意,您也可以使用自定义 buildTypes。我有一个模拟器的 buildType,所以我将模拟器编译添加到我的 gradle 文件中。如果您正确设置了它,当您通过 AndroidStudio 1.2.2 切换 Build Variant 时,正确的 Build Variant 将在依赖模块中涟漪。 不幸的是releaseCompile
在 gradle-experimental 中不起作用。【参考方案2】:
不确定您的配置有什么问题,但关于您的需求,我会采取不同的做法。
在 gradle 构建文件中,您可以使用 buildConfig
关键字将特定行添加到 BuildConfig.java
生成的类中。
所以你可以在build.gradle
中添加类似的操作:
release
buildConfig "public static final String USE_REPORTING = true;"
debug
buildConfig "public static final String USE_REPORTING = false;"
所以只有一个PlayerEnvConfig
与
public static final boolean USE_REPORTING = BuildConfig.USE_REPORTING;
甚至不再使用PlayerEnvConfig
并直接使用BuildConfig
类。
编辑自更新以来,语法已更改:
buildConfigField "<type>", "<name>", "<value>"
【讨论】:
谢谢 tbruyelle 我试过了(顺便说一句,这样更聪明),但问题仍然存在。问题在于,在构建以运行应用程序时,库始终以发布模式构建(即使我在 Android Studio 中选择了调试模式)。在我之前发布的链接中解释了这一点。但它是否存在任何解决方法? “调试类型由测试应用程序使用。发布类型由使用库的项目使用。”【参考方案3】:这记录在 https://code.google.com/p/android/issues/detail?id=52962 中。正如您所发现的,构建类型不会传播到库项目,也没有好的解决方法。如果您可以控制库项目的代码,则可以将调试状态设置为可变全局变量,并在启动时从主应用程序设置它。这有点像 hack,它的缺点是编译器无法优化未使用的代码路径远离发布版本,但除非发生异常情况,否则它应该可以工作。
【讨论】:
【参考方案4】:更新 - 自从发布这篇文章以来,gradle 构建过程已经取得了很大进展,因此这个答案可能不是推荐的最佳实践,新的更改甚至可能会破坏它。请自行决定。
我认为整个项目结构和配置有点混乱。假设您有以下 build.gradle 配置
sourceSets
main
manifest.srcFile 'src/main/AndroidManifest.xml'
java.srcDirs = ['src/main/java']
//resources.srcDirs = ['src/main']
//aidl.srcDirs = ['src/main']
//renderscript.srcDirs = ['src/main']
res.srcDirs = ['src/main/res']
assets.srcDirs = ['src/main/assets']
debug.setRoot('build-types/debug')
release.setRoot('build-types/release')
您的项目文件夹结构应如下所示
project_root
-src
-main
-java
-com
-example
-build-types
-debug
-java
-com
-example
-FooBar.java
-release
-java
-com
-example
-FooBar.java
FooBar.java
不能在prooject_root/src/main/java/com/example
中。它必须位于debug
和release
文件夹中,该文件夹位于src
文件夹之外但位于build-types
文件夹中。这是由setRoot('build-types/*****')
方法配置的。很多人看到 'debug/java' 和 'main/java' 感到困惑,后者在演示文稿中以 'src/main/java' 的方式引用,最终将 'debug/java' 放在 src 中,错误的文件夹。我希望这会有所帮助。
对于涉及其他库的更复杂的环境,您可以在这里查看我的答案https://***.com/a/19918834/319058
【讨论】:
【参考方案5】:这对于您自己提到的库项目是不可能的。
您可以将库项目更改为应用程序项目。这似乎工作正常(至少在理论上,我自己没有测试过)。
另一种方法是在您的应用程序项目中覆盖该类。合并时将选择您的应用程序项目类,并且您将获得这些值。
【讨论】:
据我所知,应用模块不能依赖于其他应用模块。也有一个参考,只是找不到了。 是的。我也发现了。我相信旧的构建系统可能没有传播到 gradle。【参考方案6】:正如Scott 指出的那样,这是Gradle 的一个已知缺点。作为一种解决方法,您可以使用此方法,该方法使用反射从应用程序(而不是库)获取字段值:
/**
* Gets a field from the project's BuildConfig. This is useful when, for example, flavors
* are used at the project level to set custom fields.
* @param context Used to find the correct file
* @param fieldName The name of the field-to-access
* @return The value of the field, or @code null if the field is not found.
*/
public static Object getBuildConfigValue(Context context, String fieldName)
try
Class<?> clazz = Class.forName(context.getPackageName() + ".BuildConfig");
Field field = clazz.getField(fieldName);
return field.get(null);
catch (ClassNotFoundException e)
e.printStackTrace();
catch (NoSuchFieldException e)
e.printStackTrace();
catch (IllegalAccessException e)
e.printStackTrace();
return null;
例如,要获取DEBUG
字段,只需从您的Activity
调用它:
boolean debug = (Boolean) getBuildConfigValue(this, "DEBUG");
我也在AOSP Issue Tracker上分享了这个解决方案。
【讨论】:
以上是关于在 Gradle 中为 Android 中的库项目构建变体的主要内容,如果未能解决你的问题,请参考以下文章