web-dev-qa-db-ja.com

gradleでライブラリプロジェクトをビルドする場合、BuildConfig.DEBUGは常にfalse

デバッグモードでアプリを実行すると、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変数を使用しているため、このバグが原因で適切に実行されません。

81
user1324936

これは予想される動作です。

ライブラリプロジェクトは、他のプロジェクトまたはモジュールで使用するためにリリースバリアントのみを公開します。

この問題の修正に取り組んでいますが、これは簡単なことではなく、かなりの作業が必要です。

https://code.google.com/p/Android/issues/detail?id=52962 で問題を追跡できます

51
Xavier Ducrohet

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

[〜#〜] edit [〜#〜]

issue はAndroid Studio Gradleバージョン3.0の修正済みとしてマークされています。そこではimplementation project(path: ':library')を使用できます。構成を自動的に修正します。

86
Niklas

importsを確認します。時々BuildConfigが任意のクラスのライブラリから意図せずにインポートされます。例えば:

import io.fabric.sdk.Android.BuildConfig;

この場合、BuildConfig.DEBUGは常にfalse;を返します。

import com.yourpackagename.BuildConfig;

この場合、BuildConfig.DEBUGは実際の値を返しますbuild variant。

40
Gent Berani

これは、コンテキストを必要としないことを除いて、フィルの答えに似ています。

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

回避策として、このメソッドを使用できます。このメソッドは、リフレクションを使用して、アプリ(ライブラリではなく)からフィールド値を取得します。

/**
 * 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 で共有しました。

6
Phil

デバッグフレーバーにあるかどうかを確認する正しい方法ではありませんが、次の方法でアプリ自体がデバッグ可能かどうかを確認できます。

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

別の解決策があります。

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();
2

Gradleを使用して、ビルドタイプごとに独自のBuildConfigクラスを作成できます

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

/ src/debug /.../ MyBuildConfig.Java and ...

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

/ src/release /.../ MyBuildConfig.Java

次に使用します:

if (MyBuildConfig.DEBUG)
    Log.d(TAG, "Hey! This is debug version!");
2
Cluster

これは私の回避策です:アプリモジュールの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;
}`
1
dalizhang

同じ問題がありました。私はこのようなものを思いつきました:

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
javaj

Gradleファイルでデバッグ可能なtrueを使用します。

buildTypes {
  demo{
 debuggable true
    }
  live{
 debuggable true
    }
}
0
Manikandan

BuildConfig.DEBUGはまったく信頼できません。Androidは、ビルドがデバッグモードか非デバッグモードかを示すグローバルに利用可能な内部フラグを提供しました

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

デバッグ中であれば真になります

クレジット: https://medium.com/@elye.project/checking-debug-build-the-right-way-d12da109812

0
Eldhopj

各プロジェクトbuildTypesでこれを試すことができます。

parent.allprojects.each{ project -> Android.defaultConfig.debuggable = true}
0
pablisco

私のプロジェクトには多くのライブラリモジュールがあるため、私の場合は間違ったBuildConfigをインポートしていました。修正は、私のBuildConfigモジュールの正しいappをインポートすることでした。

0
Ryan R