BuildConfig.DEBUG is altijd fout bij het bouwen van bibliotheekprojecten met graduele

BuildConfig.DEBUG werkt niet (= logisch ingesteld op false) wanneer ik mijn app in de foutopsporingsmodus uitvoert. Ik gebruik gradle om te bouwen. Ik heb een bibliotheekproject waarbij ik deze controle doe. BuildConfig.java ziet er als volgt uit in de map build debug:

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

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

}

en in de releasemap:

public static final boolean DEBUG = false;

zowel in het bibliotheekproject als in het applicatieproject.

Ik probeerde dit te omzeilen door een variabele te controleren die een klasse van mijn project is. Deze klasse erft van de bibliotheek en begint bij het opstarten.

Dit leidde tot een ander probleem: gebruik mijn DEBUG-variabele in een DataBaseProvider die vóór de toepassingsklasse wordt uitgevoerd.

76
Het is een normaal gedrag. Waar is het probleem? Je moet schakelen tussen BuildVariants
toegevoegd de auteur Gabriele Mariotti, de bron
Het BuildConfig-bestand wordt correct gegenereerd, maar tijdens runtime is het onjuist. Ik heb hetzelfde probleem.
toegevoegd de auteur jophde, de bron

12 antwoord

Met Android Studio 1.1 en met de graduele versie op 1.1 is het mogelijk:

Bibliotheek

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

EDIT:

Het probleem is zojuist gemarkeerd als gerepareerd voor de Android Studio Gradle-versie 3.0. Daar kun je gewoon implementatieproject (pad: ': bibliotheek') gebruiken en het zal de juiste configuratie automatisch selecteren.

85
toegevoegd
We moeten het onderdeel 'App' toevoegen voor elke bibliotheek die we gebruiken? Als dat zo is, is dat best vervelend ...
toegevoegd de auteur android developer, de bron
Bedankt, dit deed het werk!
toegevoegd de auteur Aykut Çevik, de bron
Wauw, ze hebben eindelijk die pagina een beetje bijgewerkt en ze hebben deze functie eindelijk toegevoegd.
toegevoegd de auteur Jared Burrows, de bron
Deze manier werkt. Maar er is een nadeel: de ": library: assembleRelease" wordt zelfs genoemd als je de ": app: assembleDebug" maakt, en dit zal resulteren in een langere bouwtijd.
toegevoegd de auteur Alan Zhiliang Feng, de bron
Schone oplossing en werkt geweldig.
toegevoegd de auteur FMontano, de bron
@Konica Langere nalooptijd is een kleine prijs om te betalen - het is ingewikkelde en lange tijd sowieso !! Dit werkte wonderwel! Goed gedaan!
toegevoegd de auteur Radu, de bron
Leuke oplossing, maar als ik op "invalidate and restart" op Android Studio druk, toont het me een foutmelding: Fout: Module ': bibliotheek' heeft variant 'release' geselecteerd, maar de module '': app '' hangt af van de foutopsporing van de variant ' .
toegevoegd de auteur anber, de bron
Dit zou het gemarkeerde juiste antwoord moeten zijn;) magie gebeurt hier hehehe bedankt
toegevoegd de auteur Santi Iglesias, de bron
Uitstekende oplossing, zou het geaccepteerde antwoord moeten zijn.
toegevoegd de auteur natanavra, de bron

Dit is het verwachte gedrag hiervoor.

Bibliotheekprojecten publiceren alleen hun release-varianten voor consumptie door andere projecten of modules.

We werken eraan dit probleem te verhelpen, maar dit is niet triviaal en vereist een aanzienlijke hoeveelheid werk.

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

50
toegevoegd
Wat wordt hier verwacht? Het treedt op voor bibliotheken die zich binnen het project bevinden, dus waarom kan het niet worden ingesteld op true wanneer ik het hele project in de foutopsporingsmodus uitvoert ...
toegevoegd de auteur android developer, de bron
Dat is niet langer het geval. Daar is een goede oplossing voor. Zie mijn antwoord voor meer informatie.
toegevoegd de auteur Niklas, de bron
@XavierDucrohet Dit is een onverwacht en contra-intuïtief gedrag. Je moet zeker proberen het te repareren als je kunt.
toegevoegd de auteur Radu, de bron
Dat is waar, maar het moet handmatig worden gedaan, en schaalt niet erg goed met smaken. We willen dit in de toekomst meer automatisch maken.
toegevoegd de auteur Xavier Ducrohet, de bron
De oplossing van DodoEnte in issue tracker werkt prima, geen noodzaak voor een omweg.
toegevoegd de auteur 3c71, de bron
Tijdelijke oplossing: instAed van BuildConfig.DEBUG maakt een andere booleaanse variabele op lib-projecten, bijvoorbeeld BuildConfig.RELEASE en koppel het met het buildType van de toepassing. Details: gist.github.com/almozavr/d59e770d2a6386061fcb
toegevoegd de auteur Aleksey Malevaniy, de bron

Controleer op imports , soms BuildConfig wordt onbedoeld uit een willekeurige bibliotheekklasse geïmporteerd. Bijvoorbeeld:

import io.fabric.sdk.android.BuildConfig;

In dit geval retourneert BuildConfig.DEBUG altijd false ;

import com.yourpackagename.BuildConfig;

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

37
toegevoegd
Dit was het geval met mij.
toegevoegd de auteur Subin Sebastian, de bron
Life Saver, bedankt ...
toegevoegd de auteur Arif Nadeem, de bron
@SubinSebastian me ook.
toegevoegd de auteur user1510006, de bron

Dit is als het antwoord van Phil, behalve dat het de context niet nodig heeft:

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
toegevoegd
@Rolf ツ Nou, je zou in plaats daarvan de applicatie-context kunnen gebruiken.
toegevoegd de auteur android developer, de bron
Volgens dit ( blog.javia.org/static-the-android-application -package ) blogbericht mag u de methode currentPackageName nooit van een andere thread dan de activiteitssdraad (UI-thread) noemen. Coole oplossing echter.
toegevoegd de auteur Rolf ツ, de bron

Als een tijdelijke oplossing kunt u deze methode gebruiken, waarbij reflectie wordt gebruikt om de veldwaarde van de app te verkrijgen (niet de bibliotheek):

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

Als u bijvoorbeeld het veld DEBUG wilt ophalen, belt u dit gewoon vanuit uw Activiteit :

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

Ik heb deze oplossing ook gedeeld op de AOSP Issue Tracker .

6
toegevoegd
@shkschneider welke regel? Kun je je uitzondering posten?
toegevoegd de auteur Phil, de bron
Zou nuttig kunnen zijn voor anderen: pas op voor het gebruik van applicationIdSuffix in Gradle, waardoor de klasse .BuildConfig niet bereikbaar zou zijn met de bovenstaande code.
toegevoegd de auteur shkschneider, de bron
Deze oplossing biedt mij StackOverflowError ...
toegevoegd de auteur shkschneider, de bron

Niet echt de juiste manier om te controleren of u zich in de foutopsporing bevindt, maar u kunt controleren of de app zelf is te debuggen via:

private static Boolean sIsDebuggable;

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

Het standaardgedrag van apps en bibliotheken komt perfect overeen.

Als u een betere oplossing nodig hebt, kunt u deze in plaats daarvan gebruiken:

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
toegevoegd

Hier is nog een oplossing.

1) Maak een interface

public interface BuildVariantDetector {

    boolean isDebugVariant();

}

2) Gebruik deze interface op applicatieklasse (applicatiemodule)

public class MyApplication extends Application implements BuildVariantDetector {

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

}

3) En dan in bibliotheekmodule:

boolean debugVariant = ((BuildVariantDetector)getApplication()).isDebugVariant();
2
toegevoegd
Eenvoudige en elegante oplossing. Zorg er wel voor dat u de BuildConfig van de app-module niet die van de bibliotheek importeert. Dat is een zeer stiekeme fout.
toegevoegd de auteur WindRider, de bron
Dit werkt niet. BuildConfig.DEBUG is nog steeds onwaar voor mij.
toegevoegd de auteur DiscDev, de bron

U kunt uw eigen BuildConfig-klasse maken voor elk bouwtype met behulp van gradle

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

voor /src/debug /.../ MyBuildConfig.java en ...

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

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

Gebruik dan:

if (MyBuildConfig.DEBUG)
    Log.d(TAG, "Hey! This is debug version!");
2
toegevoegd
Is "..." voor de pakketnaam van de bibliotheek? Als dat zo is, lijkt dit niet te werken. Ik heb geen toegang tot de klas.
toegevoegd de auteur android developer, de bron

We hadden hetzelfde probleem. Ik kwam met zoiets als dit:

We hebben een SDK (bibliotheek) en een demoproject, de hiërarchie ziet er als volgt uit:

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

Voor de demo-app die we hebben, waren : SDK: jarjarDebug en : SDK: jarjarRelease zijn enkele specifieke taken voor : SDK die enige post-productie opleveren verwerkte potten:

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

Dit werkt zelfs voor meerdere ingebouwde buildTypes . Debuggen is echter een beetje moeilijk. Geef alstublieft commentaar.

1
toegevoegd

In mijn geval was ik de verkeerde BuildConfig aan het importeren omdat mijn project veel bibliotheekmodules bevat. De oplossing was om de juiste BuildConfig te importeren voor mijn module app .

0
toegevoegd

Je zou dit kunnen proberen in elk van de projecten buildTypes:

parent.allprojects.each{ project -> android.defaultConfig.debuggable = true}
0
toegevoegd
Kun je het alsjeblieft uitleggen? Voeg het alleen toe aan het "debug" buildType? En aan elk van de modules? Het geeft me een foutmelding: Fout: (31, 0) Geen enkele eigenschap: debuggable voor klasse: com.android.build.gradle.internal.dsl.ProductFlavor_Decorate & zwnj; d
toegevoegd de auteur android developer, de bron
Kun je het alsjeblieft bekijken en het antwoord bijwerken? Als er een eenvoudige oplossing is, wil ik dat graag weten.
toegevoegd de auteur android developer, de bron
De specs van de android gradle plugin zijn veranderd, dus dit is niet langer geldig. De foutopsporingsvlag is verplaatst naar het buildType en niet naar de buildconfiguratie. De theorie die de debug-ondertekening instelt, zou dezelfde truc moeten doen
toegevoegd de auteur pablisco, de bron

Dit is mijn oplossing: reflecteren BuildConfig van app-module:

`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
toegevoegd