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 2013

回答:


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年

課題追跡システムでDodoEnteが提供するソリューションは問題なく機能し、回避策は必要ありません。
3c71 2015年

もはやそうではありません。そのための適切な解決策があります。詳細については、私の回答を参照しください。
Niklas 2015年

それは本当ですが、手動で行う必要があり、フレーバーにうまく対応できません。将来的にはこれをより自動化したいと考えています。
Xavier Ducrohet 2015年

@XavierDucrohetこれは、予期しない、直感に反する動作です。可能であれば、間違いなく修正を試みる必要があります。
ラドゥ2015

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 StudioGradleバージョン3.0で修正済みとしてマークされました。そこで使用するだけでimplementation project(path: ':library')、正しい構成が自動的に選択されます。


5
この方法は機能します。ただし、欠点があります。「:app:assembleDebug」を作成しているときにも「:library:assembleRelease」が呼び出されるため、ビルド時間が長くなります。
Alan Zhiliang Feng 2015

うわー、彼らはついにそのページを少し更新し、ついにこの機能を追加しました。
Jared Burrows 2015年

おかげで、これは仕事をしました!
AykutÇevik

@Konica Longer Gradleのビルド時間は、支払うべき小さな代償です-とにかく複雑で長い時間です!! これは素晴らしく機能しました!よくやった!
ラドゥ2015

使用するライブラリごとに「アプリ」の部分を追加する必要がありますか?もしそうなら、...非常に迷惑なんだ
Androidデベロッパー

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メソッドを呼び出さないでください。しかし、クールな解決策。
ロルフツ2016年

@Rolfツ代わりにapplication-contextを使用できます。
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 IssueTrackerでも共有しています。


@shkschneider何行?例外を投稿できますか?
フィル

3
他の人に役立つかもしれません:上記のコードからクラスに到達できなくapplicationIdSuffixなるGradleでの使用に注意してください.BuildConfig
shkschneider 2015年

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に「...」はありますか?もしそうなら、これはうまくいかないようです。クラスにアクセスできません。
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は私にとってまだfalseです。
DiscDev 2016年

シンプルでエレガントなソリューション。ライブラリではなく、アプリモジュールのBuildConfigをインポートしてください。それは非常に卑劣な間違いです。
WindRider 2017

1

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

SDK(ライブラリ)とデモプロジェクトがあり、階層は次のようになります。

Parent
  |
  + SDK (:SDK)
  |
  + DemoApp (:DemoApp)

私たちが持っているデモアプリの場合、いくつかの後処理されたjarを生成するためのいくつかの特定のタスクが: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でフレーバーを使用できます。
AbhinavSaxena19年

0

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

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

説明してもらえますか?「デバッグ」buildTypeにのみ追加しますか?そして、各モジュールに?エラーが発生します:エラー:(31,0)そのようなプロパティはありません:クラスに対してデバッグ可能:com.android.build.gradle.internal.dsl.ProductFlavor_Decorated –android
開発者

android gradleプラグインの仕様が変更されたため、これは無効になりました。デバッグ可能なフラグはbuildType、ビルド構成ではなく、に移動されました。理論的には、デバッグ署名を設定しても同じトリックを実行する必要があります
pablisco 2016

確認して回答を更新していただけますか?簡単な回避策があれば、それについて知りたいのですが。
Androidデベロッパー

0

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


0

gradleファイルでdebuggabletrueを操作します。

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.