Pytanie BuildConfig.DEBUG zawsze ma wartość false podczas budowania projektów bibliotek ze stopniem


BuildConfig.DEBUG nie działa (= logicznie ustawione na false), gdy uruchamiam moją aplikację w trybie debugowania. Używam gradle do kompilacji. Mam projekt biblioteki, w którym to sprawdzam. BuildConfig.java wygląda tak w folderze debugowania kompilacji:

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

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

}

oraz w folderze release:

public static final boolean DEBUG = false;

zarówno w projekcie bibliotecznym, jak iw projekcie aplikacji.

Próbowałem obejść to poprzez sprawdzenie zmiennej, która jest ustawiona klasa mojego projektu. Ta klasa dziedziczy z biblioteki i rozpoczyna się przy starcie.

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

Doprowadziło to do innego problemu: użyj mojej zmiennej DEBUG w DataBaseProvider, która działa przed klasą aplikacji.


76
2017-11-24 15:29


pochodzenie


To normalne zachowanie. Gdzie jest problem? Musisz przełączać się między BuildVariants - Gabriele Mariotti
Plik BuildConfig jest generowany poprawnie, ale w czasie wykonywania jest fałszywy. Mam ten sam problem. - jophde


Odpowiedzi:


Jest to oczekiwane zachowanie.

Projekty biblioteczne publikują jedynie swoje warianty wydania do wykorzystania przez inne projekty lub moduły.

Pracujemy nad naprawieniem tego, ale nie jest to trywialne i wymaga znacznej ilości pracy.

Możesz śledzić problem na stronie https://code.google.com/p/android/issues/detail?id=52962


50
2017-12-16 18:18



Obejście: instaed z BuildConfig.DEBUG utworzyć inną zmienną boolean w lib-projektu, np. BuildConfig.RELEASE i połącz go z buildType aplikacji. Detale: gist.github.com/almozavr/d59e770d2a6386061fcb - Aleksey Malevaniy
Rozwiązanie dostarczone przez DodoEnte w narzędziu do śledzenia problemów działa dobrze, bez potrzeby obejścia. - 3c71
Tak już nie jest. Istnieje na to odpowiednie rozwiązanie. Widzieć moja odpowiedź po więcej informacji. - Niklas
To prawda, ale musi być zrobione ręcznie i nie skaluje się zbyt dobrze ze smakami. Chcemy uczynić to bardziej automatycznym w przyszłości. - Xavier Ducrohet
@XavierDucrohet Jest to nieoczekiwane i sprzeczne z intuicją zachowanie. Powinieneś zdecydowanie spróbować to naprawić, jeśli możesz. - Radu


Z Androidem 1.1 i wersją gradową na poziomie 1.1 jest to możliwe:

Biblioteka

android {
    publishNonDefault true
}

App

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

Kompletną dokumentację można znaleźć tutaj http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Library-Publication

EDYTOWAĆ:

The kwestia został właśnie oznaczony jako poprawiony dla Androida Studio Gradle w wersji 3.0. Tam możesz po prostu użyć implementation project(path: ':library') i automatycznie wybierze poprawną konfigurację.


85
2018-03-20 09:32



W ten sposób działa. Istnieje jednak pewna wada: nazwa ": library: assembleRelease" jest wywoływana nawet podczas tworzenia ": app: assembleDebug", a to spowoduje dłuższy czas budowy. - Alan Zhiliang Feng
Wow, w końcu zaktualizowali tę stronę troszkę i w końcu dodali tę funkcję. - Jared Burrows
Dzięki, to się stało! - Aykut Çevik
Doskonałe rozwiązanie, powinno być przyjętą odpowiedzią. - natanavra
Czyste rozwiązanie i działa świetnie. - FMontano


Sprawdzić imports, czasami BuildConfig jest nieumyślnie importowany z dowolnej klasy biblioteki. Na przykład:

import io.fabric.sdk.android.BuildConfig;

W tym przypadku BuildConfig.DEBUG zawsze wróci fałszywy;

import com.yourpackagename.BuildConfig;

W tym przypadku BuildConfig.DEBUG zwróci twoje prawdziwe wariant budowy.


37
2017-07-14 11:49



Tak było w moim przypadku. - Subin Sebastian
@SubinSebastian ja też. - user1510006
Life Saver, dzięki ... - Arif Nadeem


To jest jak odpowiedź Phila, ale nie potrzebuje kontekstu:

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

7
2018-02-03 02:55



Według tego (blog.javia.org/static-the-android-application-package) wpis na blogu, że nigdy nie należy wywoływać metody currentPackageName z żadnego wątku innego niż wątek aktywności (wątek UI). Fajne rozwiązanie. - Rolf ツ
@Rolf ツ Cóż, zamiast tego możesz użyć kontekstu aplikacji. - android developer


Aby obejść ten problem, możesz użyć tej metody, która używa odbicia, aby uzyskać wartość pola z aplikacji (nie biblioteki):

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

Aby uzyskać DEBUG pole, na przykład, po prostu wywołaj to ze swojego Activity:

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

Ja również udostępniłem to rozwiązanie w Internecie AESP Śledzenie problemów.


6
2017-08-27 01:41



To obejście daje mi StackOverflowError... - shkschneider
@Shkschneider jaka linia? Czy możesz opublikować swój wyjątek? - Phil
Może być użyteczny dla innych: uważaj na użycie applicationIdSuffix w Gradle, który uczyniłby .BuildConfig klasa nieosiągalna z powyższego kodu. - shkschneider


Naprawdę nie jest to właściwy sposób sprawdzania, czy jesteś w stanie debugowania, ale możesz sprawdzić, czy sama aplikacja jest dostępna do debugowania przez:

private static Boolean sIsDebuggable;

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

Domyślne zachowanie aplikacji i bibliotek idealnie do siebie pasuje.

Jeśli potrzebujesz lepszego rozwiązania, możesz użyć tego zamiast:

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
2018-06-21 09:51





Możesz stworzyć własną klasę BuildConfig dla każdego typu kompilacji używając gradle

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

dla /src/debug/.../MyBuildConfig.java i...

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

dla /src/release/.../MyBuildConfig.java

Następnie użyj:

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

2
2017-10-19 15:08



Czy "..." dla packageName biblioteki? Jeśli tak, to wydaje się nie działać. Nie mogę uzyskać dostępu do klasy. - android developer


Oto inne rozwiązanie.

1) Utwórz interfejs

public interface BuildVariantDetector {

    boolean isDebugVariant();

}

2) Użyj tego interfejsu w klasie Application (moduł Appplication)

public class MyApplication extends Application implements BuildVariantDetector {

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

}

3) A następnie w module bibliotecznym:

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

2
2018-05-06 12:59



To nie działa. BuildConfig.DEBUG wciąż jest dla mnie fałszywy. - DiscDev
Proste i eleganckie rozwiązanie. Tylko pamiętaj, by importować moduł BuildConfig modułu aplikacji, a nie biblioteki. To bardzo podstępny błąd. - WindRider