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.