可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
BuildConfig.DEBUG is not working (= logically set to false) when I run my app in debug mode. I use gradle to build.I have a library project where I do this check. BuildConfig.java looks like this in the build debug folder:
/** Automatically generated file. DO NOT MODIFY */ package common.myProject; public final class BuildConfig { public static final boolean DEBUG = Boolean.parseBoolean("true"); }
and in the release folder:
public static final boolean DEBUG = false;
both in the library project and in the application project.
I tried to get around this by checking a variable which is set a class of my project. This class inherits from the library and starts on startup.
<application android:name=".MyPrj" ...
This led to another problem: is use my DEBUG variable in a DataBaseProvider which runs before the application class.
回答1:
This is expected behavior for this.
Library projects only publish their release variants for consumption by other projects or modules.
We're working at fixing this but this is non trivial and requires a significant amount of work.
You can track the issue at https://code.google.com/p/android/issues/detail?id=52962
回答2:
With Android Studio 1.1 and having also the gradle version at 1.1 it is possible:
Library
android { publishNonDefault true }
App
dependencies { releaseCompile project(path: ':library', configuration: 'release') debugCompile project(path: ':library', configuration: 'debug') }
Complete documentation can be found here http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Library-Publication
EDIT:
The issue has just been marked as fixed for the Android Studio Gradle Version 3.0. There you can just use implementation project(path: ':library')
and it'll select the correct configuration automatically.
回答3:
Check for imports
, sometimes BuildConfig is imported from any class of library unintentionally. For example:
import io.fabric.sdk.android.BuildConfig;
In this case BuildConfig.DEBUG will always return false;
import com.yourpackagename.BuildConfig;
In this case BuildConfig.DEBUG will return your real build variant.
回答4:
This is like Phil's answer except it doesn't need the context:
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; }
回答5:
As a workaround, you can use this method, which uses reflection to get the field value from the app (not the library):
/** * 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; }
To get the DEBUG
field, for example, just call this from your Activity
:
boolean debug = (Boolean) getBuildConfigValue(this, "DEBUG");
I have also shared this solution on the AOSP Issue Tracker.
回答6:
You can create your own BuildConfig class for each build type using gradle
public class MyBuildConfig { public static final boolean DEBUG = true; }
for /src/debug/.../MyBuildConfig.java and...
public class MyBuildConfig { public static final boolean DEBUG = false; }
for /src/release/.../MyBuildConfig.java
Then use:
if (MyBuildConfig.DEBUG) Log.d(TAG, "Hey! This is debug version!");
回答7:
Here is another solution.
1) Create an interface
public interface BuildVariantDetector { boolean isDebugVariant(); }
2) Use this interface on Application class (Appplication module)
public class MyApplication extends Application implements BuildVariantDetector { @Override public boolean isDebugVariant() { return BuildConfig.DEBUG; //application (main module) Buildonfig } }
3) And then in library module:
boolean debugVariant = ((BuildVariantDetector)getApplication()).isDebugVariant();
回答8:
We had the same problem. I came up with something like this:
We have a SDK (library) and a demo project, hierarchy looks like this:
Parent | + SDK (:SDK) | + DemoApp (:DemoApp)
For the demo app we have, were :SDK:jarjarDebug
and :SDK:jarjarRelease
are some specific tasks for :SDK
that produce some post-processed jars:
dependencies { debugCompile tasks.getByPath(":SDK:jarjarDebug").outputs.files releaseCompile tasks.getByPath(":SDK:jarjarRelease").outputs.files ... more dependencies ... }
This works even for multiple buildTypes
built at once. Debugging is a bit difficult though. Please comment.
回答9:
Not really the correct way to check if you are in debug flavor, but you can check if the app itself is debuggable via:
private static Boolean sIsDebuggable; public static boolean isDebuggable(Context context) { if (sIsDebuggable == null) sIsDebuggable = (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; return sIsDebuggable; }
The default behavior of apps and libraries will match it perfectly.
If you need a better workaround, you can use this instead:
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; }
回答10:
You could try this on each of the projects buildTypes:
parent.allprojects.each{ project -> android.defaultConfig.debuggable = true}
回答11:
In my case I was importing the wrong BuildConfig
as my project has many library modules. The fix was to import the correct BuildConfig
for my app
module.
回答12:
This is my workaround: reflect BuildConfig of app module:
`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; }`