22

我正在尝试使用 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中读到的内容,该库仅在测试时使用调试模式。

有任何想法吗?

谢谢!

4

6 回答 6

16

这是来自谷歌代码问题的@bifmadei 答案,它对我有帮助:

过时 1:尝试在依赖项目中设置此项

android {
    publishNonDefault true
    ...
}

过时 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指令分离releaseCompiledebugCompile过时:https ://stackoverflow.com/a/44364851/3379437

更新

上一步中的方法仍然可以与自定义构建配置一起使用:

implementation project(path: ':theotherproject', configuration: 'staging')
于 2014-09-25T11:24:17.570 回答
12

不确定您的配置有什么问题,但关于您的需求,我会采取不同的做法。

在 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>"
于 2013-07-04T12:03:48.540 回答
4

这记录在https://code.google.com/p/android/issues/detail?id=52962中。正如您所发现的,构建类型不会传播到库项目,并且没有好的解决方法。如果您可以控制库项目的代码,则可以将调试状态设置为可变全局变量,并在启动时从主应用程序设置它。这有点像 hack,它的缺点是编译器无法优化未使用的代码路径远离发布版本,但除非发生异常情况,否则它应该可以工作。

于 2013-11-13T22:36:01.943 回答
3

更新 - 自从发布这篇文章以来,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. 它必须在debugrelease文件夹中,该文件夹位于文件夹之外src但在文件夹内build-types。那是通过setRoot('build-types/*****')方法配置的。很多人看到 'debug/java' 和 'main/java' 感到困惑,后者在演示文稿中以 'src/main/java' 的方式引用,最终将 'debug/java' 放在 src 中,错误的文件夹。我希望这会有所帮助。

对于涉及其他库的更复杂的环境,您可以在此处查看我的答案https://stackoverflow.com/a/19918834/319058

于 2013-11-12T22:56:44.493 回答
0

正如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 问题跟踪器上分享了这个解决方案。

于 2014-08-27T01:42:56.473 回答
0

正如您自己提到的,这对于图书馆项目是不可能的。

您可以将库项目更改为应用程序项目。这似乎工作正常(至少在理论上,我自己没有测试过)。

另一种方法是在您的应用程序项目中覆盖该类。合并发生时将选择您的应用程序项目类,并且您将获得这些值。

于 2013-08-31T04:34:48.590 回答