пятница, мая 06, 2016

Gradle, conditionally include or exclude LeakCanary or something else

This example shows how to include/exculde LeakCanary and AndroidDevMetrics.

Note:
when LeakCanary (or AdnroidDevMetrics) is excluded, "standart" initialization code like

  MyApp
    onCreate() {
      LeakCanary.install(this);

will not be compiled: LeakCanary class will be not found.
So in this case I have to use reflection and Class.forName.


def useLeakCanary = false
def useAndroidDevMetrics = true

apply plugin: 'com.android.application'

if (useAndroidDevMetrics) {
    apply plugin: 'com.frogermcs.androiddevmetrics'
}

buildscript {
    repositories {
        mavenLocal()
        jcenter()
    }
    dependencies {
        ...
        classpath 'com.frogermcs.androiddevmetrics:androiddevmetrics-plugin:0.4'
    }
}

android {
    ...

    buildTypes {
        release {
            useLeakCanary = false
            buildConfigField "boolean", "USE_LEAK_CANARY", "false"

            buildConfigField "boolean", "USE_ANDROID_DEV_METRICS", "false"
            ...
        }

        debug {
            useLeakCanary = true
            buildConfigField "boolean", "USE_LEAK_CANARY", "$useLeakCanary"

            buildConfigField "boolean", "USE_ANDROID_DEV_METRICS", "$useAndroidDevMetrics"
        }
    }
}

dependencies {
    ...

    if (useLeakCanary) {
        debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1'
        releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'
        testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'
    }
}

-------------------


public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        if (BuildConfig.USE_ANDROID_DEV_METRICS) {
            AndroidDevMetricsWrapper.initWith this
        }

        if (BuildConfig.USE_LEAK_CANARY) {
            LeakCanaryWrapper.install this
        }
    }
}

-------------------

class AndroidDevMetricsWrapper {

    public static void initWith(Application app) {
        try {
            Class leakCanaryClass = Class.forName "com.frogermcs.androiddevmetrics.AndroidDevMetrics"
            Method initWith = leakCanaryClass.getMethod "initWith", Context.class
            initWith.invoke null, app
        } catch (Exception e) {
            Log.e "AndroidDevMetricsWrapper", Log.getStackTraceString(e)
        }
    }
}

public class LeakCanaryWrapper {

    public static void install(Application app) {
        try {
            Class leakCanaryClass = Class.forName "com.squareup.leakcanary.LeakCanary"
            Method init = leakCanaryClass.getMethod "install", Application.class
            init.invoke null, app
        } catch (Exception e) {
            Log.e "LeakCanaryWrapper", Log.getStackTraceString(e)
        }
    }

}


How to use custom gradle generated constant in android java code

It is really easy to define gradle-generated constants and use those constants in android java code.
For example, I want to use a build type dependent constant RETRY_COUNT.

Gradle's class BuildType has a method:
    public void buildConfigField(String type, String name, String value)

This method can be used like this:

android {
...

    buildTypes {
        release {
            buildConfigField "int", "RETRY_COUNT", "3"
...
        }

        debug {
            buildConfigField "int", "RETRY_COUNT", "10"
...
        }
    }
}

Next, I rebuild my project, open BuildConfig and see:

public final class BuildConfig {
...
public static final boolean RETRY_COUNT = 10;
}