BuildConfig.DEBUG всегда false при создании проектов библиотеки с помощью gradle

BuildConfig.DEBUG не работает (=логически установлено значение false) при запуске приложения в режиме отладки. Я использую Gradle для сборки.У меня есть проект библиотеки, где я делаю эту проверку. BuildConfig.java выглядит так в папке отладки сборки:

/** Automatically generated 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, который работает перед классом приложения.

12 ответов


это ожидаемое поведение для этого.

проекты библиотек публикуют только свои варианты выпуска для потребления другими проектами или модулями.

мы работаем над исправлением этого, но это нетривиально и требует значительного объема работы.

вы можете отслеживать проблему вhttps://code.google.com/p/android/issues/detail?id=52962


С Android Studio 1.1 и имея также версию gradle в 1.1 можно:

библиотека

android {
    publishNonDefault true
}

App

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') и он автоматически выберет правильную конфигурацию.


проверить imports, иногда BuildConfig импортируется из любого класса библиотеки непреднамеренно. Например:

import io.fabric.sdk.android.BuildConfig;

В этом случае BuildConfig.DEBUG всегда будет возвращать false;

import com.yourpackagename.BuildConfig;

В этом случае BuildConfig.DEBUG вернет ваш реальный построить вариант.


это похоже на ответ Фила, за исключением того, что ему не нужен контекст:

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

в качестве обходного пути, вы можете использовать этот метод, который использует отражение, чтобы получить значение поля из приложения (не в библиотеке):

/**
 * 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 проблема Tracker.


не совсем правильный способ проверить, находитесь ли вы в debug flavor, но вы можете проверить, является ли само приложение отладочным через:

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

вы можете создать свой собственный класс BuildConfig для каждого типа сборки с помощью gradle

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!");

вот еще одно решение.

1) создать интерфейс

public interface BuildVariantDetector {

    boolean isDebugVariant();

}

2) Используйте этот интерфейс в классе приложений (модуль Appplication)

public class MyApplication extends Application implements BuildVariantDetector {

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

}

3) А потом в библиотечном модуле:

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

у нас была такая же проблема. Я придумал что-то вроде этого:--7-->

у нас есть 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 построен сразу. Однако отладка немного сложна. Пожалуйста, прокомментируйте.


вы можете попробовать это на каждом из проектов buildTypes:

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

В моем случае я импортировал неправильно BuildConfig поскольку мой проект имеет много библиотечных модулей. Исправление состояло в том, чтобы импортировать правильный BuildConfig для меня app модуль.


Это мое решение: отразить 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;
}`