ChatGPT解决这个技术问题 Extra ChatGPT

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

当我在调试模式下运行我的应用程序时,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");

}

并在发布文件夹中:

public static final boolean DEBUG = false;

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

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

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

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

这是一种正常的行为。问题出在哪里?您必须在 BuildVariants 之间切换
BuildConfig 文件生成正确,但在运行时它是错误的。我有同样的问题。

N
Niklas

使用 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,issue 刚刚被标记为已修复。您可以在此处使用 implementation project(path: ':library'),它会自动选择正确的配置。


这种方式有效。但是有一个缺点:即使你正在制作“:app:assembleDebug”,也会调用“:library:assembleRelease”,这会导致构建时间更长。
哇,他们终于更新了那个页面,他们终于添加了这个功能。
谢谢,这完成了工作!
@Konica Longer Gradle 构建时间是一个很小的代价——无论如何,它很复杂而且很长!!这非常有效!做得好!
我们需要为我们使用的每个库添加“App”部分吗?如果是这样,那就太烦人了……
X
Xavier Ducrohet

这是预期的行为。

库项目仅发布其发布变体以供其他项目或模块使用。

我们正在努力解决这个问题,但这并非易事,需要大量工作。

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


解决方法:代替 BuildConfig.DEBUG 在 lib-project 处创建另一个布尔变量,例如 BuildConfig.RELEASE 并将其与应用程序的 buildType 链接。详细信息:gist.github.com/almozavr/d59e770d2a6386061fcb
DodoEnte 在问题跟踪器中提供的解决方案工作得很好,不需要变通方法。
情况不再如此。有一个适当的解决方案。有关详细信息,请参阅 my answer
这是真的,但它必须手动完成,并且不能很好地适应口味。我们希望在未来使其更加自动化。
@XavierDucrohet 这是一种意想不到的反直觉行为。如果可以的话,你绝对应该尝试修复它。
G
Gent

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

import io.fabric.sdk.android.BuildConfig;

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

import com.yourpackagename.BuildConfig;

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


J
Jared Rummler

这就像菲尔的答案,除了它不需要上下文:

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ツ好吧,您可以改用应用程序上下文。
P
Phil

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

/**
 * 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 上分享了这个解决方案。


@shkschneider 什么线路?你能发布你的例外吗?
可能对其他人有用:请注意在 Gradle 中使用 applicationIdSuffix 会使上述代码无法访问 .BuildConfig 类。
a
android developer

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

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

C
Cluster

您可以使用 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 是否为“...”?如果是这样,这似乎不起作用。我无法访问课程。
D
Dominik Suszczewicz

这是另一个解决方案。

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 对我来说仍然是错误的。
简单而优雅的解决方案。只要确保您导入应用程序模块的 BuildConfig 而不是库的。这是一个非常狡猾的错误。
j
javaj

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

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

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

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

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

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


R
Ryan R

在我的情况下,我导入了错误的 BuildConfig,因为我的项目有很多库模块。解决方法是为我的 app 模块导入正确的 BuildConfig


d
dalizhang

这是我的解决方法:反映应用模块的 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 中使用风味。
p
pablisco

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

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

你能解释一下吗?仅将其添加到“调试” buildType?和每个模块?它给了我一个错误:错误:(31、0)没有这样的属性:类可调试:com.android.build.gradle.internal.dsl.ProductFlavor_Decorated
android gradle 插件的规格已更改,因此不再有效。可调试标志已移至 buildType 而不是构建配置。我理论上设置调试签名应该做同样的伎俩
你能检查一下并更新答案吗?如果有一个简单的解决方法,我想知道它。
M
Manikandan

在 gradle 文件中使用 debuggable true。

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

E
Eldhopj

BuildConfig.DEBUG 根本不可靠,Android 提供了一个全局可用的内部标志,指示构建是处于调试模式还是非调试模式

(getContext().getApplicationInfo().flags &ApplicationInfo.FLAG_DEBUGGABLE) != 0) 

如果它在调试中将是真的

学分:https://medium.com/@elye.project/checking-debug-build-the-right-way-d12da1098120