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


83

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" ...

Это приводит к другой проблеме: я использую свою переменную DEBUG в DataBaseProvider, которая запускается перед классом приложения, и она не будет работать должным образом из-за этой ошибки.


Это нормальное поведение. В чем проблема? Вы должны переключаться между BuildVariants
— Габриэле Мариотти

1
Файл BuildConfig создан правильно, но во время выполнения он неверен. У меня такая же проблема.
— jophde

Ответы:


52

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

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

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

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


4
Обходной путь: при установке BuildConfig.DEBUG создайте еще одну логическую переменную в lib-проекте, например, BuildConfig.RELEASE, и свяжите ее с buildType приложения. Подробности: gist.github.com/almozavr/d59e770d2a6386061fcb
— Алексей Малованый

Решение, предоставленное DodoEnte в системе отслеживания проблем, работает нормально, нет необходимости в обходном пути.
— 3c71 05

Это уже не так. Для этого есть подходящее решение. См. Мой ответ для получения дополнительной информации.
— Niklas

Это правда, но это нужно делать вручную, и это не очень хорошо сочетается с ароматами. Мы хотим сделать это более автоматическим в будущем.
— Ксавье Дюкро,

@XavierDucrohet Это неожиданное и противоречащее интуиции поведение. Вы обязательно должны попытаться исправить это, если сможете.
— Radu

86

С Android Studio 1.1, а также с версией Gradle 1.1 возможно:

Библиотека

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. Там вы можете просто использовать, implementation project(path: ':library')и он автоматически выберет правильную конфигурацию.


5
Так работает. Но есть недостаток: ": library: assemblyRelease" вызывается даже в том случае, если вы создаете ": app: AssemblyDebug", и это приведет к увеличению времени сборки.
— Алан Чжилян Фэн

Вау, они наконец-то немного обновили эту страницу и наконец добавили эту функцию.
— Джаред Берроуз

Спасибо, это сработало!
— Aykut evik

Время сборки @Konica Longer Gradle - небольшая плата - в любом случае, это запутанно и долго !! Это сработало чудесно! Отлично сработано!
— Radu

Нам нужно добавить часть «Приложение» для каждой библиотеки, которую мы используем? Если так, то это довольно неприятно ...
— разработчик Android

47

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

import io.fabric.sdk.android.BuildConfig;

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

import com.yourpackagename.BuildConfig;

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


8

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

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 ) вы никогда не должны вызывать метод currentPackageName из любого потока, кроме потока активности (потока пользовательского интерфейса). Но крутое решение.
— Rolf ツ

@Rolf: Вместо этого вы могли бы использовать контекст приложения.
— разработчик Android

6

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

/**
 * 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 .


@shkschneider какая строчка? Вы можете опубликовать свое исключение?
— Фил

3
Может быть полезно другим: остерегайтесь использования applicationIdSuffixв Gradle, которое сделает .BuildConfigкласс недоступным из этого кода выше.
— шкшнейдер

5

Не совсем правильный способ проверить, используете ли вы отладочную версию, но вы можете проверить, можно ли отладить само приложение с помощью:

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

2

Вы можете создать свой собственный класс 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!");

Имеет ли "..." имя пакета библиотеки? Если так, похоже, это не работает. Я не могу получить доступ к классу.
— разработчик Android

2

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

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 для меня по-прежнему неверен.
— DiscDev

Простое и элегантное решение. Просто убедитесь, что вы импортируете BuildConfig модуля приложения, а не библиотеку. Это очень коварная ошибка.
— WindRider 07

1

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

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


1

Это мой обходной путь: отразите 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.
— Абхинав Саксена

0

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

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

Не могли бы вы объяснить? Добавить только в buildType "отладки"? А к каждому из модулей? Это дает мне ошибку: Ошибка: (31, 0) Нет такого свойства: debuggable для класса: com.android.build.gradle.internal.dsl.ProductFlavor_Decorated
— разработчик Android

Спецификации плагина android gradle изменились, поэтому он больше не действителен. Флаг отлаживаемости был перемещен в buildTypeконфигурацию сборки, а не в ее. Теоретически настройка подписи отладки должна сделать тот же трюк
— pablisco

Не могли бы вы проверить это и обновить ответ? Если есть простой обходной путь, я хотел бы знать об этом.
— разработчик Android

0

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


0

Работа с debuggable true в файле gradle.

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

0

BuildConfig.DEBUG вообще ненадежен, Android предоставил внутренний флаг, который доступен во всем мире, указывая, находится ли сборка в режиме отладки или без нее.

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

будет правдой, если он находится в отладке

Кредиты: https://medium.com/@elye.project/checking-debug-build-the-right-way-d12da1098120

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.