BuildConfig.DEBUG siempre es falso cuando se crean proyectos de biblioteca con gradle

BuildConfig.DEBUG no funciona (= configurado lógicamente como falso) cuando ejecuto mi aplicación en modo de depuración. Uso gradle para compilar. Tengo un proyecto de biblioteca donde hago esta comprobación. BuildConfig.java se ve así en la carpeta de depuración de compilación:

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

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

}

y en la carpeta de lanzamiento:

public static final boolean DEBUG = false;

Tanto en el proyecto de la biblioteca como en el proyecto de la aplicación.

Traté de evitar esto al verificar una variable que se establece una clase de mi proyecto. Esta clase hereda de la biblioteca y comienza en el inicio.

Esto llevó a otro problema: es usar mi variable DEBUG en un DataBaseProvider que se ejecuta antes de la clase de aplicación.

76
Es un comportamiento normal. ¿Dónde está el problema? Tienes que cambiar entre BuildVariants
agregado el autor Gabriele Mariotti, fuente
El archivo BuildConfig se genera correctamente pero en tiempo de ejecución es falso. Tengo el mismo problema.
agregado el autor jophde, fuente

12 Respuestas

Con Android Studio 1.1 y teniendo también la versión gradle en 1.1 es posible:

Biblioteca

android {
    publishNonDefault true
}

Aplicación

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

EDIT:

El problema se acaba de marcar como corregido para la versión 3.0 de Android Studio Gradle. Allí puede utilizar el proyecto de implementación (ruta: ': library') y seleccionará la configuración correcta automáticamente.

85
agregado
¿Necesitamos agregar la parte de "Aplicación" para cada biblioteca que usamos? Si es así, eso es bastante molesto ...
agregado el autor android developer, fuente
Gracias, esto hizo el trabajo!
agregado el autor Aykut Çevik, fuente
Wow, finalmente actualizaron esa página un poco y finalmente agregaron esta función.
agregado el autor Jared Burrows, fuente
De esta manera funciona. Pero hay un inconveniente: el ": library: assembleRelease" se llama incluso a través de usted está haciendo el ": app: assembleDebug", y esto resultará en un tiempo de construcción más largo.
agregado el autor Alan Zhiliang Feng, fuente
Solución limpia y funciona muy bien.
agregado el autor FMontano, fuente
El tiempo de construcción de @Konica Longer Gradle es un precio pequeño a pagar, ¡es complicado y es un tiempo largo de todos modos! ¡Esto funcionó maravillosamente! ¡Bien hecho!
agregado el autor Radu, fuente
Buena solución, pero si presiono "invalidar y reiniciar" en Android Studio, me muestra un error: Error: El módulo ': library' tiene la variante 'versión' seleccionada, pero el módulo '': app '' depende de la variante 'debug' .
agregado el autor anber, fuente
Esta debe ser la respuesta correcta marcada;) la magia sucede aquí jejeje, gracias
agregado el autor Santi Iglesias, fuente
Excelente solución, debe ser la respuesta aceptada.
agregado el autor natanavra, fuente

Este es el comportamiento esperado para esto.

Los proyectos de biblioteca solo publican sus variantes de publicación para el consumo de otros proyectos o módulos.

Estamos trabajando para solucionar esto, pero esto no es trivial y requiere una cantidad significativa de trabajo.

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

50
agregado
¿Qué se espera aquí? Ocurre para las bibliotecas que están dentro del proyecto en sí, por lo tanto, ¿por qué no se puede establecer en verdadero cuando ejecuto todo el proyecto en modo de depuración ...
agregado el autor android developer, fuente
Ese ya no es el caso. Hay una solución adecuada para eso. Consulte mi respuesta para obtener más información.
agregado el autor Niklas, fuente
@XavierDucrohet Este es un comportamiento inesperado y contra intuitivo. Definitivamente deberías intentar arreglarlo si puedes.
agregado el autor Radu, fuente
Eso es cierto, pero tiene que hacerse manualmente y no se adapta muy bien a los sabores. Queremos hacer esto más automático en el futuro.
agregado el autor Xavier Ducrohet, fuente
La solución provista por DodoEnte en el rastreador de problemas funciona bien, sin necesidad de una solución alternativa.
agregado el autor 3c71, fuente
Solución alternativa: instaed de BuildConfig.DEBUG crear otra variable booleana, por ejemplo, en el proyecto lib-project. BuildConfig.RELEASE y vincúlela con buildType de la aplicación. Detalles: gist.github.com/almozavr/d59e770d2a6386061fcb
agregado el autor Aleksey Malevaniy, fuente

Compruebe si hay importaciones , a veces BuildConfig se importa de cualquier clase de biblioteca sin querer. Por ejemplo:

import io.fabric.sdk.android.BuildConfig;

En este caso, BuildConfig.DEBUG siempre devolverá false ;

import com.yourpackagename.BuildConfig;

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

37
agregado
Este fue el caso conmigo.
agregado el autor Subin Sebastian, fuente
Salvavidas, gracias ...
agregado el autor Arif Nadeem, fuente
@SubinSebastian yo también.
agregado el autor user1510006, fuente

Esta es como la respuesta de Phil, excepto que no necesita el contexto:

private static Boolean sDebug;

/**
 * Is {@link BuildConfig#DEBUG} still broken for library projects? If so, use this.

* * See: https://code.google.com/p/android/issues/detail?id=52962

* * @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; }
7
agregado
@Rolf ツ Bueno, podrías usar el contexto de la aplicación en su lugar.
agregado el autor android developer, fuente
De acuerdo con esto ( blog.javia.org/static-the-android-application -paquete ) en la publicación de blog, nunca debe llamar al método currentPackageName desde cualquier hilo que no sea el hilo de actividad (hilo UI). Buena solución sin embargo.
agregado el autor Rolf ツ, fuente

Como solución alternativa, puede utilizar este método, que utiliza la reflexión para obtener el valor de campo de la aplicación (no de la biblioteca):

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

Para obtener el campo DEBUG , por ejemplo, simplemente llame a esto desde su Activity :

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

También he compartido esta solución en el AOSP Issue Tracker .

6
agregado
@shkschneider qué línea? ¿Puedes publicar tu excepción?
agregado el autor Phil, fuente
Podría ser útil para otros: tenga cuidado con el uso de applicationIdSuffix en Gradle que haría que la clase .BuildConfig no sea accesible desde este código anterior.
agregado el autor shkschneider, fuente
Esta solución me da StackOverflowError ...
agregado el autor shkschneider, fuente

No es realmente la forma correcta de verificar si está en la versión de depuración, pero puede verificar si la aplicación en sí es debugable a través de:

private static Boolean sIsDebuggable;

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

El comportamiento predeterminado de las aplicaciones y las bibliotecas coincidirá perfectamente.

Si necesita una solución alternativa mejor, puede usar esto en su lugar:

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

Aquí hay otra solución.

1) Crear una interfaz

public interface BuildVariantDetector {

    boolean isDebugVariant();

}

2) Utilice esta interfaz en la clase de aplicación (módulo de aplicación)

public class MyApplication extends Application implements BuildVariantDetector {

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

}

3) Y luego en el módulo de biblioteca:

boolean debugVariant = ((BuildVariantDetector)getApplication()).isDebugVariant();
2
agregado
Solución simple y elegante. Solo asegúrese de importar el BuildConfig del módulo de la aplicación, no de la biblioteca. Ese es un error muy astuto.
agregado el autor WindRider, fuente
Esto no funciona. BuildConfig.DEBUG sigue siendo falso para mí.
agregado el autor DiscDev, fuente

Puedes crear tu propia clase BuildConfig para cada tipo de compilación usando gradle

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

para /src/debug/.../MyBuildConfig.java y ...

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

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

Luego use:

if (MyBuildConfig.DEBUG)
    Log.d(TAG, "Hey! This is debug version!");
2
agregado
¿"..." para el nombre de paquete de la biblioteca? Si es así, esto no parece funcionar. No puedo acceder a la clase.
agregado el autor android developer, fuente

Tuvimos el mismo problema. Se me ocurrió algo como esto:

Tenemos un SDK (biblioteca) y un proyecto de demostración, la jerarquía se ve así:

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

Para la aplicación de demostración que tenemos, fueron : SDK: jarjarDebug y : SDK: jarjarRelease son algunas tareas específicas para : SDK que producen algunas publicaciones posteriores. tarros procesados

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

Esto funciona incluso para varios buildTypes construidos a la vez. Sin embargo, la depuración es un poco difícil. Por favor comenta.

1
agregado

En mi caso, estaba importando el BuildConfig incorrecto ya que mi proyecto tiene muchos módulos de biblioteca. La solución fue importar el BuildConfig correcto para mi aplicación .

0
agregado

Puedes probar esto en cada uno de los proyectos buildTypes:

parent.allprojects.each{ project -> android.defaultConfig.debuggable = true}
0
agregado
¿Puede usted explicar por favor? ¿Agregarlo al buildType "debug" solamente? ¿Y a cada uno de los módulos? Me da un error: Error: (31, 0) No existe tal propiedad: debuggable for class: com.android.build.gradle.internal.dsl.ProductFlavor_Decorate & zwnj; d
agregado el autor android developer, fuente
¿Puedes por favor verificarlo y actualizar la respuesta? Si hay una solución fácil, me gustaría saberlo.
agregado el autor android developer, fuente
Las especificaciones del complemento gradle de Android han cambiado, por lo que esto ya no es válido. El indicador de depuración se ha movido al buildType y no a la configuración de compilación. La teoría de configurar la firma de depuración debería hacer el mismo truco
agregado el autor pablisco, fuente

Esta es mi solución: Reflejar BuildConfig del módulo de la aplicación:

`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;
}`
0
agregado