使用gradle构建库项目时,BuildConfig.DEBUG始终为false


83

当我在调试模式下运行应用程序时,BuildConfig.DEBUG无法正常工作(=逻辑上设置为false)。我使用Gradle构建。我有一个图书馆项目,我要检查一下。BuildConfig.java在构建调试文件夹中如下所示:

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

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

}

并在release文件夹中:

public static final boolean DEBUG = false;

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

我试图通过检查设置项目类的变量来解决此问题。此类从库继承,并在启动时开始。

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

这导致了另一个问题:是我在DataBaseProvider中使用了DEBUG变量,该变量在应用程序类之前运行,并且由于此错误而无法正常运行。


这是正常现象。问题出在哪里?您必须在BuildVariants之间切换
Gabriele Mariotti

1
BuildConfig文件已正确生成,但在运行时为false。我有同样的问题。
jophde

Answers:


52

这是预期的行为。

库项目仅发布其发行版本,以供其他项目或模块使用。

我们正在努力解决此问题,但这并不简单,需要大量工作。

您可以通过https://code.google.com/p/android/issues/detail?id=52962跟踪问题


4
解决方法:在BuildConfig.DEBUG位置创建一个布尔变量,在lib项目的BuildConfig.RELEASE处创建,并将其与应用程序的buildType链接。详细信息:gist.github.com/almozavr/d59e770d2a6386061fcb
Oleksii Malovanyi 2014年

DodoEnte在问题跟踪器中提供的解决方案可以很好地工作,不需要解决方法。
3c71

情况不再如此。有一个适当的解决方案。请参阅我的答案以获取更多信息。
尼古拉斯

没错,但这必须手动完成,并且无法很好地扩展口味。我们希望在将来使其更加自动化。
Xavier Ducrohet

@XavierDucrohet这是意外的和相反的直观行为。如果可以的话,您绝对应该尝试修复它。
Radu

86

使用Android Studio 1.1并具有1.1的gradle版本,可以:

图书馆

android {
    publishNonDefault true
}

应用程式

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

完整的文档可以在这里找到http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Library-Publication

编辑

问题刚刚被标记为Android Studio Gradle 3.0版已修复。您可以在那里使用implementation project(path: ':library')它,它会自动选择正确的配置。


5
这种方式有效。但是有一个缺点:即使通过创建“:app:assembleDebug”也会调用“:library:assembleRelease”,这将导致更长的构建时间。
冯志良

哇,他们终于对该页面进行了少许更新,并最终添加了此功能。
Jared Burrows 2015年

谢谢,这完成了工作!
AykutÇevik15年

@Konica Longer Gradle的构建时间是一个很小的代价-无论如何它都是令人费解的和长期的!!这很棒!做得好!
Radu

我们需要为我们使用的每个库添加“应用程序”部分吗?如果是这样,那就太烦人了……
android开发人员

46

检查imports,有时BuildConfig是无意地从任何类库导入的。例如:

import io.fabric.sdk.android.BuildConfig;

在这种情况下,BuildConfig.DEBUG将始终返回false

import com.yourpackagename.BuildConfig;

在这种情况下,BuildConfig.DEBUG将返回您的实际构建变体。


8

这类似于Phil的答案,但它不需要上下文:

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

根据此(blog.javia.org/static-the-android-application-package)博客文章,您永远不要从活动线程(UI线程)以外的任何线程调用currentPackageName方法。虽然很酷的解决方案。
罗夫·ツ

@Rolfツ好吧,您可以改用应用程序上下文。
Android开发人员

6

解决方法是,您可以使用此方法,该方法使用反射从应用程序(而不是库)获取字段值:

/**
 * 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问题跟踪器上共享了该解决方案。


@shkschneider什么行?您可以发布例外吗?
菲尔(Phil)2015年

3
可能对其他人有用:当心applicationIdSuffix在Gradle中的使用,这将使.BuildConfig上面的代码无法访问该类。
shkschneider

5

并不是检查您是否处于调试状态的正确方法,但是您可以通过以下方法检查应用程序本身是否可调试:

private static Boolean sIsDebuggable;

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

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

如果您需要更好的解决方法,则可以改用以下方法:

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

2

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

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

对于/src/debug/.../MyBuildConfig.java和...

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

对于/src/release/.../MyBuildConfig.java

然后使用:

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

库的packageName是否为“ ...”?如果是这样,这似乎不起作用。我无法上课。
Android开发人员

2

这是另一种解决方案。

1)创建一个界面

public interface BuildVariantDetector {

    boolean isDebugVariant();

}

2)在应用程序类(应用程序模块)上使用此接口

public class MyApplication extends Application implements BuildVariantDetector {

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

}

3)然后在库模块中:

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

这行不通。BuildConfig.DEBUG对我来说仍然是假的。
DiscDev '16

简单而优雅的解决方案。只需确保导入应用模块的BuildConfig而不是库的即可。这是一个非常狡猾的错误。
WindRider

1

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

我们有一个SDK(库)和一个演示项目,层次结构如下所示:

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

对于演示程序,我们有,是:SDK:jarjarDebug:SDK:jarjarRelease是为某些特定的任务:SDK产生了一些后处理罐:

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

这甚至适用buildTypes于一次构建的多个。但是调试有点困难。请评论。


1

这是我的解决方法:反映应用模块的BuildConfig:

`public static boolean debug = 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;
}`

您已经使用了反射,但这不是必需的。您可以在build.gradle中使用风味。
Abhinav Saxena

0

您可以在每个项目的buildTypes上尝试以下操作:

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

你能解释一下吗?仅将其添加到“调试” buildType吗?以及每个模块?它给我一个错误:错误:(31,0)没有这样的属性:可调试的类:com.android.build.gradle.internal.dsl.ProductFlavor_Decorated
android developer

android gradle插件的规格已更改,因此不再有效。可调试标志已移至buildType而非构建配置。我认为设置调试签名应该做同样的技巧
pablisco

您能检查一下并更新答案吗?如果有一个简单的解决方法,我想知道。
Android开发人员

0

就我而言,我导入的是错误的,BuildConfig因为我的项目有很多库模块。解决方法是BuildConfig为我的app模块导入正确的文件。


0

在gradle文件中使用可调试true。

buildTypes {
  demo{
 debuggable true
    }
  live{
 debuggable true
    }
}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.