简体   繁体   English

在Gradle中为Android中的库项目构建变体

[英]Build variants in Gradle for a Library Project in Android

I am trying to configure with Gradle a project which contains some external libraries. 我正在尝试使用Gradle配置一个包含一些外部库的项目。 With Gradle I can setup different Environmental Configuration (with a class inside a config file) for the main application using the Build Variants so I can execute code according to this variables. 使用Gradle我可以使用Build Variants为主应用程序设置不同的环境配置(在配置文件中有一个类),这样我就可以根据这些变量执行代码。

The problem is that how I can do the same for a library project? 问题是我如何为图书馆项目做同样的事情? I created this library for this project and I would like to setup different Build Variants for different scenarios. 我为这个项目创建了这个库,我想为不同的场景设置不同的Build Variants。

As an example: In the Library, when running in debug mode, then print all the logs so I can see them while developing. 例如:在库中,当在调试模式下运行时,然后打印所有日志,以便我可以在开发时看到它们。 In release mode dont. 在发布模式下不要。

Structure of the files: 文件结构:

src ----- > debug -> java -> config -> PlayerEnvConfig
            main -> com.mypackagename -> etc...
            release -> java -> config -> PlayerEnvConfig

Code in debug: package config; debug中的代码: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;
}

Code in release: 发布代码:

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;
}

The problem is that for the main project I can use this Build types to configure differently the application for different scenarios, but how can I do the same for the Library Project? 问题是,对于主项目,我可以使用此Build类型为不同场景配置不同的应用程序,但我如何为库项目执行相同操作?

Because at the moment from what I read in http://tools.android.com/tech-docs/new-build-system/user-guide the library only will use the debug mode while testing. 因为目前我在http://tools.android.com/tech-docs/new-build-system/user-guide中读到的内容,库只会在测试时使用调试模式。

Any ideas? 有任何想法吗?

Thanks! 谢谢!

It's a @bifmadei answer from google code issue and it helps for me: 这是来自谷歌代码问题的@bifmadei答案,它对我有帮助:

Try setting this in the dependency project 尝试在依赖项目中设置它

android {
    publishNonDefault true
    ...
}

and this in the project that uses it 这在使用它的项目中

dependencies {
    releaseCompile project(path: ':theotherproject', configuration: 'release')
    debugCompile project(path: ':theotherproject', configuration: 'debug')
}

Taken from here: https://code.google.com/p/android/issues/detail?id=66805 摘自此处: https//code.google.com/p/android/issues/detail? id = 66805

Not sure what's wrong with your configuration but about your need, I would do it differently. 不确定您的配置有什么问题,但有关您的需求,我会采用不同的方式。

In the gradle build file you can use the buildConfig keyword to add a specific line to the BuildConfig.java generated class. 在gradle构建文件中,您可以使用buildConfig关键字将特定行添加到BuildConfig.java生成的类中。

So you could add do something like that in your build.gradle : 所以你可以在build.gradle添加类似的东西:

    release {
        buildConfig "public static final String USE_REPORTING = true;"
    }
    debug {

        buildConfig "public static final String USE_REPORTING = false;"
    }

And so have only one PlayerEnvConfig with 所以只有一个PlayerEnvConfig

public static final boolean USE_REPORTING = BuildConfig.USE_REPORTING;

Or even no more PlayerEnvConfig and use directly the BuildConfig class. 甚至没有更多的PlayerEnvConfig并直接使用BuildConfig类。


EDIT Since an update, the syntax has changed : 编辑自更新以来,语法已更改:

buildConfigField "<type>", "<name>", "<value>"

This is documented in https://code.google.com/p/android/issues/detail?id=52962 . 这在https://code.google.com/p/android/issues/detail?id=52962中有记录。 As you've found out, the build type isn't propagated to library projects, and there isn't a good workaround. 正如您所知,构建类型不会传播到库项目,并且没有一个好的解决方法。 If you have control over the code of the library project, you could make the debug status a mutable global variable, and set it from your main application on startup. 如果您可以控制库项目的代码,则可以将调试状态设置为可变全局变量,并在启动时从主应用程序设置它。 It's a bit of a hack, and it has the disadvantage that the compiler can't optimize the unused code paths away from release builds, but unless something unusual is going on it should work. 这有点像黑客,它的缺点是编译器无法优化未使用的代码路径远离发布版本,但除非发生异常,否则它应该有效。

UPDATE - since the time of this posting, there have been much progress in the gradle build process, thus this answer might not be the recommended best practice and new changes might even brake it. 更新 - 自发布之日起,gradle构建过程取得了很大进展,因此这个答案可能不是推荐的最佳实践,新的更改甚至可能会使其失效。 Use your own discretion. 自行决定。

I believe that there is a bit of confusion over the whole project structure and configuration. 我认为整个项目结构和配置存在一些混乱。 Let's say that you have the following build.gradle configuration 假设您有以下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')
}

Your project folder structure should be as follow 您的项目文件夹结构应如下所示

project_root
   -src
      -main
         -java
            -com
               -example
   -build-types
      -debug
         -java
            -com
               -example
                  -FooBar.java
      -release
         -java
            -com
               -example
                  -FooBar.java

FooBar.java must not be in the prooject_root/src/main/java/com/example . FooBar.java不能在prooject_root/src/main/java/com/example It must be in debug and release folder which is to reside outside src folder but inside build-types folder. 它必须位于debugrelease文件夹中,该文件夹位于src文件夹之外但位于build-types文件夹中。 That is configured by setRoot('build-types/*****') method. 这是由setRoot('build-types/*****')方法配置的。 A lot of people get confused from seeing 'debug/java' and 'main/java', where the later is referenced in a manner 'src/main/java' from presentation and end up putting 'debug/java' in src, the wrong folder. 很多人因为看到'debug / java'和'main / java'而感到困惑,后者在演示中以'src / main / java'的方式引用,最后在src中放入'debug / java',错文件夹。 I hope this help. 我希望这有帮助。

For more complex environment involving other libraries, you can check out my answer here https://stackoverflow.com/a/19918834/319058 对于涉及其他库的更复杂的环境,您可以在这里查看我的答案https://stackoverflow.com/a/19918834/319058

This is not possible with library projects as you yourself mentioned. 对于您自己提到的库项目,这是不可能的。

You could just change the library project to an application project. 您可以将库项目更改为应用程序项目。 That seems to work fine (at least in theory, I haven't tested it myself). 这似乎工作正常(至少在理论上,我自己没有测试过)。

The other way would be to override that class in your application project. 另一种方法是在应用程序项目中覆盖该类。 Your application project class will be chosen when merging takes place and you'll have those values available. 合并发生时将选择您的应用程序项目类,并且您将获得这些值。

As Scott points out, this is a known shortcoming of Gradle . 斯科特指出,这是Gradle的一个众所周知的缺点。 As a workaround, you can use this method, which uses reflection to get the field value from the app (not the library): 作为一种变通方法,您可以使用此方法,该方法使用反射从应用程序(而不是库)获取字段值:

/**
 * 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;
}

To get the DEBUG field, for example, just call this from your Activity : 例如,要获取DEBUG字段,只需从您的Activity调用:

boolean debug = (Boolean) getBuildConfigValue(this, "DEBUG");

I have also shared this solution on the AOSP Issue Tracker . 我也在AOSP问题跟踪器上分享了这个解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM