BuildConfig。在使用gradle构建库项目时,调试总是错误的。

时间:2022-11-10 08:40:00

BuildConfig.DEBUG is not working (= logically set to false) when I run my app in debug mode. I use gradle to build.I have a library project where I do this check. BuildConfig.java looks like this in the build debug folder:

BuildConfig。当我在调试模式下运行我的应用程序时,DEBUG不工作(=逻辑设置为false)。我用gradle来构建。我有一个图书馆项目,我在那里做这个检查。BuildConfig。java在构建调试文件夹中是这样的:

/** Automatically generated file. DO NOT MODIFY */
package common.myProject;

public final class BuildConfig {
    public static final boolean DEBUG = Boolean.parseBoolean("true");

}

and in the release folder:

在发布文件夹中:

public static final boolean DEBUG = false;

both in the library project and in the application project.

在库项目和应用程序项目中都有。

I tried to get around this by checking a variable which is set a class of my project. This class inherits from the library and starts on startup.

我试图通过检查一个变量来绕过这个问题,这个变量设置了我的项目的一个类。这个类继承自库并在启动时启动。

<application
        android:name=".MyPrj" ...

This led to another problem: is use my DEBUG variable in a DataBaseProvider which runs before the application class.

这导致了另一个问题:在应用程序类之前运行的数据库提供程序中使用我的调试变量。

12 个解决方案

#1


50  

This is expected behavior for this.

这是预期的行为。

Library projects only publish their release variants for consumption by other projects or modules.

库项目只发布它们的版本,供其他项目或模块使用。

We're working at fixing this but this is non trivial and requires a significant amount of work.

我们正在努力解决这个问题,但这不是小事,需要大量的工作。

You can track the issue at https://code.google.com/p/android/issues/detail?id=52962

您可以在https://code.google.com/p/android/issue /detail?id=52962上跟踪这个问题。

#2


85  

With Android Studio 1.1 and having also the gradle version at 1.1 it is possible:

有了Android Studio 1.1,也有了1.1版本的版本,这是可能的:

Library

图书馆

android {
    publishNonDefault true
}

App

应用程序

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

Complete documentation can be found here http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Library-Publication

完整的文档可以在这里找到:http://tools.android.com/tech-docs/new- buildsystem/userguide # toc - libr-publication。

EDIT:

编辑:

The issue has just been marked as fixed for the Android Studio Gradle Version 3.0. There you can just use implementation project(path: ':library') and it'll select the correct configuration automatically.

这个问题刚刚被标记为Android Studio Gradle 3.0版本。您可以使用实现项目(path: ':library'),它将自动选择正确的配置。

#3


37  

Check for imports, sometimes BuildConfig is imported from any class of library unintentionally. For example:

检查导入,有时会无意中从任何类库导入BuildConfig。例如:

import io.fabric.sdk.android.BuildConfig;

In this case BuildConfig.DEBUG will always return false;

在这种情况下BuildConfig。调试总是返回false;

import com.yourpackagename.BuildConfig;

In this case BuildConfig.DEBUG will return your real build variant.

在这种情况下BuildConfig。调试将返回您真正的构建版本。

#4


7  

This is like Phil's answer except it doesn't need the context:

这就像菲尔的答案,只是不需要上下文:

private static Boolean sDebug;

/**
 * Is {@link BuildConfig#DEBUG} still broken for library projects? If so, use this.</p>
 * 
 * See: https://code.google.com/p/android/issues/detail?id=52962</p>
 * 
 * @return {@code true} if this is a debug build, {@code false} if it is a production build.
 */
public static boolean isDebugBuild() {
    if (sDebug == null) {
        try {
            final Class<?> activityThread = Class.forName("android.app.ActivityThread");
            final Method currentPackage = activityThread.getMethod("currentPackageName");
            final String packageName = (String) currentPackage.invoke(null, (Object[]) null);
            final Class<?> buildConfig = Class.forName(packageName + ".BuildConfig");
            final Field DEBUG = buildConfig.getField("DEBUG");
            DEBUG.setAccessible(true);
            sDebug = DEBUG.getBoolean(null);
        } catch (final Throwable t) {
            final String message = t.getMessage();
            if (message != null && message.contains("BuildConfig")) {
                // Proguard obfuscated build. Most likely a production build.
                sDebug = false;
            } else {
                sDebug = BuildConfig.DEBUG;
            }
        }
    }
    return sDebug;
}

#5


6  

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:

例如,要获得调试字段,只需从活动中调用它:

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

I have also shared this solution on the AOSP Issue Tracker.

我也在AOSP问题跟踪器上分享了这个解决方案。

#6


2  

You can create your own BuildConfig class for each build type using gradle

您可以使用gradle为每个构建类型创建自己的BuildConfig类。

public class MyBuildConfig
{
    public static final boolean DEBUG = true;
}

for /src/debug/.../MyBuildConfig.java and...

/ src /调试/…/ MyBuildConfig。java和…

public class MyBuildConfig
{
    public static final boolean DEBUG = false;
}

for /src/release/.../MyBuildConfig.java

/ src /释放/…/ MyBuildConfig.java

Then use:

然后使用:

if (MyBuildConfig.DEBUG)
    Log.d(TAG, "Hey! This is debug version!");

#7


2  

Here is another solution.

这是另一个解决方案。

1) Create an interface

1)创建一个接口

public interface BuildVariantDetector {

    boolean isDebugVariant();

}

2) Use this interface on Application class (Appplication module)

2)在Application类(Appplication模块)上使用此接口

public class MyApplication extends Application implements BuildVariantDetector {

    @Override
    public boolean isDebugVariant() {
        return BuildConfig.DEBUG; //application (main module) Buildonfig
    }

}

3) And then in library module:

3)在图书馆模块:

boolean debugVariant = ((BuildVariantDetector)getApplication()).isDebugVariant();

#8


1  

We had the same problem. I came up with something like this:

我们遇到了同样的问题。我想到了这样的事情:

We have a SDK (library) and a demo project, hierarchy looks like this:

我们有一个SDK(库)和一个演示项目,层次结构是这样的:

Parent
  |
  + SDK (:SDK)
  |
  + DemoApp (:DemoApp)

For the demo app we have, were :SDK:jarjarDebug and :SDK:jarjarRelease are some specific tasks for :SDK that produce some post-processed jars:

对于演示应用程序,我们有:SDK:jarjarDebug和:SDK:jarjarRelease是一些特定的任务:生成一些后处理jar的SDK:

dependencies {
    debugCompile tasks.getByPath(":SDK:jarjarDebug").outputs.files
    releaseCompile tasks.getByPath(":SDK:jarjarRelease").outputs.files
    ... more dependencies ...
}

This works even for multiple buildTypes built at once. Debugging is a bit difficult though. Please comment.

这甚至适用于同时构建的多个构建类型。不过调试有点困难。请发表评论。

#9


1  

Not really the correct way to check if you are in debug flavor, but you can check if the app itself is debuggable via:

这并不是检查你是否在调试味道的正确方法,但是你可以检查这个应用程序本身是否可以调试:

private static Boolean sIsDebuggable;

public static boolean isDebuggable(Context context) {
    if (sIsDebuggable == null)
        sIsDebuggable = (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
    return sIsDebuggable;
}

The default behavior of apps and libraries will match it perfectly.

应用程序和库的默认行为将与它完美匹配。

If you need a better workaround, you can use this instead:

如果你需要更好的变通方法,你可以用这个代替:

public static boolean isInDebugFlavour(Context context) {
    if (sDebugFlavour == null) {
        try {
            final String packageName = context.getPackageName();
            final Class<?> buildConfig = Class.forName(packageName + ".BuildConfig");
            final Field DEBUG = buildConfig.getField("DEBUG");
            DEBUG.setAccessible(true);
            sDebugFlavour = DEBUG.getBoolean(null);
        } catch (final Throwable t) {
            sDebugFlavour = false;
        }
    }
    return sDebugFlavour;
}

#10


0  

You could try this on each of the projects buildTypes:

您可以在每一个项目的构建类型上尝试这个:

parent.allprojects.each{ project -> android.defaultConfig.debuggable = true}

#11


0  

In my case I was importing the wrong BuildConfig as my project has many library modules. The fix was to import the correct BuildConfig for my app module.

在我的例子中,我导入了错误的BuildConfig,因为我的项目有许多库模块。修复程序是为我的应用程序模块导入正确的BuildConfig。

#12


0  

This is my workaround: reflect BuildConfig of app module:

这是我的工作:体现app模块的BuildConfig:

`public static boolean debug = isDebug();

“公共静态布尔调试= isDebug();

private static boolean isDebug() {
    boolean result = false;
    try {
        Class c = Class.forName("com.example.app.BuildConfig");
        Field f = c.getField("DEBUG");
        f.setAccessible(true);
        result = f.getBoolean(c);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
    return result;
}`

#1


50  

This is expected behavior for this.

这是预期的行为。

Library projects only publish their release variants for consumption by other projects or modules.

库项目只发布它们的版本,供其他项目或模块使用。

We're working at fixing this but this is non trivial and requires a significant amount of work.

我们正在努力解决这个问题,但这不是小事,需要大量的工作。

You can track the issue at https://code.google.com/p/android/issues/detail?id=52962

您可以在https://code.google.com/p/android/issue /detail?id=52962上跟踪这个问题。

#2


85  

With Android Studio 1.1 and having also the gradle version at 1.1 it is possible:

有了Android Studio 1.1,也有了1.1版本的版本,这是可能的:

Library

图书馆

android {
    publishNonDefault true
}

App

应用程序

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

Complete documentation can be found here http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Library-Publication

完整的文档可以在这里找到:http://tools.android.com/tech-docs/new- buildsystem/userguide # toc - libr-publication。

EDIT:

编辑:

The issue has just been marked as fixed for the Android Studio Gradle Version 3.0. There you can just use implementation project(path: ':library') and it'll select the correct configuration automatically.

这个问题刚刚被标记为Android Studio Gradle 3.0版本。您可以使用实现项目(path: ':library'),它将自动选择正确的配置。

#3


37  

Check for imports, sometimes BuildConfig is imported from any class of library unintentionally. For example:

检查导入,有时会无意中从任何类库导入BuildConfig。例如:

import io.fabric.sdk.android.BuildConfig;

In this case BuildConfig.DEBUG will always return false;

在这种情况下BuildConfig。调试总是返回false;

import com.yourpackagename.BuildConfig;

In this case BuildConfig.DEBUG will return your real build variant.

在这种情况下BuildConfig。调试将返回您真正的构建版本。

#4


7  

This is like Phil's answer except it doesn't need the context:

这就像菲尔的答案,只是不需要上下文:

private static Boolean sDebug;

/**
 * Is {@link BuildConfig#DEBUG} still broken for library projects? If so, use this.</p>
 * 
 * See: https://code.google.com/p/android/issues/detail?id=52962</p>
 * 
 * @return {@code true} if this is a debug build, {@code false} if it is a production build.
 */
public static boolean isDebugBuild() {
    if (sDebug == null) {
        try {
            final Class<?> activityThread = Class.forName("android.app.ActivityThread");
            final Method currentPackage = activityThread.getMethod("currentPackageName");
            final String packageName = (String) currentPackage.invoke(null, (Object[]) null);
            final Class<?> buildConfig = Class.forName(packageName + ".BuildConfig");
            final Field DEBUG = buildConfig.getField("DEBUG");
            DEBUG.setAccessible(true);
            sDebug = DEBUG.getBoolean(null);
        } catch (final Throwable t) {
            final String message = t.getMessage();
            if (message != null && message.contains("BuildConfig")) {
                // Proguard obfuscated build. Most likely a production build.
                sDebug = false;
            } else {
                sDebug = BuildConfig.DEBUG;
            }
        }
    }
    return sDebug;
}

#5


6  

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:

例如,要获得调试字段,只需从活动中调用它:

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

I have also shared this solution on the AOSP Issue Tracker.

我也在AOSP问题跟踪器上分享了这个解决方案。

#6


2  

You can create your own BuildConfig class for each build type using gradle

您可以使用gradle为每个构建类型创建自己的BuildConfig类。

public class MyBuildConfig
{
    public static final boolean DEBUG = true;
}

for /src/debug/.../MyBuildConfig.java and...

/ src /调试/…/ MyBuildConfig。java和…

public class MyBuildConfig
{
    public static final boolean DEBUG = false;
}

for /src/release/.../MyBuildConfig.java

/ src /释放/…/ MyBuildConfig.java

Then use:

然后使用:

if (MyBuildConfig.DEBUG)
    Log.d(TAG, "Hey! This is debug version!");

#7


2  

Here is another solution.

这是另一个解决方案。

1) Create an interface

1)创建一个接口

public interface BuildVariantDetector {

    boolean isDebugVariant();

}

2) Use this interface on Application class (Appplication module)

2)在Application类(Appplication模块)上使用此接口

public class MyApplication extends Application implements BuildVariantDetector {

    @Override
    public boolean isDebugVariant() {
        return BuildConfig.DEBUG; //application (main module) Buildonfig
    }

}

3) And then in library module:

3)在图书馆模块:

boolean debugVariant = ((BuildVariantDetector)getApplication()).isDebugVariant();

#8


1  

We had the same problem. I came up with something like this:

我们遇到了同样的问题。我想到了这样的事情:

We have a SDK (library) and a demo project, hierarchy looks like this:

我们有一个SDK(库)和一个演示项目,层次结构是这样的:

Parent
  |
  + SDK (:SDK)
  |
  + DemoApp (:DemoApp)

For the demo app we have, were :SDK:jarjarDebug and :SDK:jarjarRelease are some specific tasks for :SDK that produce some post-processed jars:

对于演示应用程序,我们有:SDK:jarjarDebug和:SDK:jarjarRelease是一些特定的任务:生成一些后处理jar的SDK:

dependencies {
    debugCompile tasks.getByPath(":SDK:jarjarDebug").outputs.files
    releaseCompile tasks.getByPath(":SDK:jarjarRelease").outputs.files
    ... more dependencies ...
}

This works even for multiple buildTypes built at once. Debugging is a bit difficult though. Please comment.

这甚至适用于同时构建的多个构建类型。不过调试有点困难。请发表评论。

#9


1  

Not really the correct way to check if you are in debug flavor, but you can check if the app itself is debuggable via:

这并不是检查你是否在调试味道的正确方法,但是你可以检查这个应用程序本身是否可以调试:

private static Boolean sIsDebuggable;

public static boolean isDebuggable(Context context) {
    if (sIsDebuggable == null)
        sIsDebuggable = (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
    return sIsDebuggable;
}

The default behavior of apps and libraries will match it perfectly.

应用程序和库的默认行为将与它完美匹配。

If you need a better workaround, you can use this instead:

如果你需要更好的变通方法,你可以用这个代替:

public static boolean isInDebugFlavour(Context context) {
    if (sDebugFlavour == null) {
        try {
            final String packageName = context.getPackageName();
            final Class<?> buildConfig = Class.forName(packageName + ".BuildConfig");
            final Field DEBUG = buildConfig.getField("DEBUG");
            DEBUG.setAccessible(true);
            sDebugFlavour = DEBUG.getBoolean(null);
        } catch (final Throwable t) {
            sDebugFlavour = false;
        }
    }
    return sDebugFlavour;
}

#10


0  

You could try this on each of the projects buildTypes:

您可以在每一个项目的构建类型上尝试这个:

parent.allprojects.each{ project -> android.defaultConfig.debuggable = true}

#11


0  

In my case I was importing the wrong BuildConfig as my project has many library modules. The fix was to import the correct BuildConfig for my app module.

在我的例子中,我导入了错误的BuildConfig,因为我的项目有许多库模块。修复程序是为我的应用程序模块导入正确的BuildConfig。

#12


0  

This is my workaround: reflect BuildConfig of app module:

这是我的工作:体现app模块的BuildConfig:

`public static boolean debug = isDebug();

“公共静态布尔调试= isDebug();

private static boolean isDebug() {
    boolean result = false;
    try {
        Class c = Class.forName("com.example.app.BuildConfig");
        Field f = c.getField("DEBUG");
        f.setAccessible(true);
        result = f.getBoolean(c);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
    return result;
}`