Gradle로 라이브러리 프로젝트를 빌드 할 때 BuildConfig.DEBUG는 항상 false입니다.


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

이로 인해 또 다른 문제가 발생합니다. 응용 프로그램 클래스 이전에 실행되는 DataBaseProvider에서 DEBUG 변수를 사용하고이 버그로 인해 제대로 실행되지 않습니다.


정상적인 동작입니다. 문제는 어디입니까? BuildVariants간에 전환해야합니다
Gabriele Mariotti

1
BuildConfig 파일은 올바르게 생성되지만 런타임에는 false입니다. 나는 같은 문제가 있습니다.
jophde

답변:


52

이것은 예상되는 동작입니다.

라이브러리 프로젝트는 다른 프로젝트 또는 모듈에서 사용할 수 있도록 릴리스 변형 만 게시합니다.

우리는이 문제를 해결하기 위해 노력하고 있지만 이것은 사소한 것이 아니며 상당한 작업이 필요합니다.

https://code.google.com/p/android/issues/detail?id=52962 에서 문제를 추적 할 수 있습니다.


4
해결 방법 : BuildConfig.DEBUG를 설치하면 lib-project의 BuildConfig.RELEASE와 같은 또 다른 부울 변수를 생성하고이를 응용 프로그램의 buildType과 연결합니다. 세부 정보 : gist.github.com/almozavr/d59e770d2a6386061fcb
Oleksii Malovanyi 2014-06-26

DodoEnte가 이슈 트래커에서 제공하는 솔루션은 문제를 해결할 필요없이 잘 작동합니다.
3c71 2015 년

더 이상 그렇지 않습니다. 이에 대한 적절한 해결책이 있습니다. 자세한 내용은 내 대답 을 참조하십시오.
Niklas

사실이지만 수동으로 수행해야하며 풍미와 잘 맞지 않습니다. 우리는 이것을 더 자동적으로 만들고 싶습니다.
Xavier Ducrohet 2015 년

@XavierDucrohet 이것은 예상치 못한 반 직관적 인 동작입니다. 가능하면 확실히 고쳐야합니다.
Radu

86

Android Studio 1.1과 1.1 버전의 gradle 버전을 사용하면 다음이 가능합니다.

도서관

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
이 방법은 작동합니다. 그러나 단점이 있습니다. ": app : assembleDebug"를 만드는 동안에도 ": library : assembleRelease"가 호출되어 빌드 시간이 길어집니다.
Alan Zhiliang Feng 2015

와우, 그들은 마침내 그 페이지 를 약간 업데이트했고 마침내이 기능을 추가했습니다.
Jared Burrows

고마워요.
Aykut Çevik 2015 년

@Konica Longer Gradle 빌드 시간은 지불해야 할 적은 비용입니다. 어쨌든 복잡하고 오랜 시간이 걸립니다 !! 이것은 훌륭하게 작동했습니다! 잘 했어!
Radu

우리가 사용하는 각 라이브러리에 대해 "App"부분을 추가해야합니까? 그렇다면, 그 ... 아주 짜증나
안드로이드 개발자는

46

을 확인하십시오 imports. 때때로 BuildConfig 가 의도하지 않게 라이브러리의 모든 클래스에서 가져옵니다. 예를 들면 :

import io.fabric.sdk.android.BuildConfig;

이 경우 BuildConfig.DEBUG 는 항상 false를 반환합니다 .

import com.yourpackagename.BuildConfig;

이 경우 BuildConfig.DEBUG 는 실제 빌드 변형을 반환합니다 .


8

이것은 컨텍스트가 필요하지 않다는 점을 제외하면 Phil의 대답과 같습니다.

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 ) 에 따르면 활동 스레드 (UI 스레드)가 아닌 다른 스레드에서 currentPackageName 메서드를 호출해서는 안됩니다. 그래도 멋진 솔루션.
Rolf ツ

@Rolf ツ 대신 응용 프로그램 컨텍스트를 사용할 수 있습니다.
안드로이드 개발자

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 Issue Tracker 에서이 솔루션을 공유했습니다 .


@shkschneider 무슨 라인? 예외를 게시 할 수 있습니까?

3
다른 사람들에게 유용 할 수 있습니다. 위의 코드에서 클래스에 접근 할 수 없게 applicationIdSuffix만드는 Gradle 의 사용에주의하십시오 .BuildConfig.
shkschneider

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

gradle을 사용하여 각 빌드 유형에 대해 고유 한 BuildConfig 클래스를 만들 수 있습니다.

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

라이브러리의 packageName에 대해 "..."가 있습니까? 그렇다면 이것은 작동하지 않는 것 같습니다. 수업에 액세스 할 수 없습니다.
안드로이드 개발자

2

여기 또 다른 해결책이 있습니다.

1) 인터페이스 생성

public interface BuildVariantDetector {

    boolean isDebugVariant();

}

2) Application 클래스 (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();

이것은 작동하지 않습니다. BuildConfig.DEBUG는 여전히 저에게 거짓입니다.
DiscDev 2016 년

간단하고 우아한 솔루션. 라이브러리가 아닌 앱 모듈의 BuildConfig를 가져와야합니다. 그것은 매우 교활한 실수입니다.
WindRider

1

우리는 같은 문제가있었습니다. 나는 다음과 같은 것을 생각 해냈다.

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한 번에 빌드 된 여러 개에서도 작동합니다 . 하지만 디버깅은 약간 어렵습니다. 의견을 부탁합니다.


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에서 특징을 사용할 수 있습니다.
Abhinav Saxena 2019

0

각 프로젝트 buildTypes에서 이것을 시도 할 수 있습니다.

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

설명해 주시겠습니까? "debug"buildType에만 추가 하시겠습니까? 그리고 각 모듈에? com.android.build.gradle.internal.dsl.ProductFlavor_Decorated : 오류 : (31, 0) 그러한 특성 : 클래스에 대한 디버깅 그것은 나에게 오류 제공
안드로이드 개발자

Android Gradle 플러그인의 사양이 변경되어 더 이상 유효하지 않습니다. 디버그 가능 플래그가 buildType빌드 구성이 아닌 로 이동되었습니다 . 디버그 서명을 설정 I 이론은 같은 트릭을 할해야
pablisco

확인하고 답변을 업데이트 해 주시겠습니까? 쉬운 해결 방법이 있다면 그것에 대해 알고 싶습니다.
안드로이드 개발자

0

제 경우에는 BuildConfig프로젝트에 라이브러리 모듈이 많기 때문에 잘못 가져 왔습니다. 수정 사항은 BuildConfigapp모듈에 대한 올바른 정보를 가져 오는 것 입니다.


0

gradle 파일에서 debuggable true로 작업합니다.

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.