Android模块化分层化之: maven 库中上传的 aar 包 获取 BuildConfig 相关常量值

来源:互联网 发布:津天元渔具淘宝网 编辑:程序博客网 时间:2024/05/21 22:24

最近在做项目分层化的一些工作,具体思路是将原有项目一些基础服务模块和设备服务模块抽离出来,上传到本地的 Maven 服务器,然后再通过在主项目中的 build.gradle 文件中通过 compile 语句进行导包处理。但通过这种方法编译成的 aar 包只能是 release 版本,无法使用到 BuildConfig 动态设置的一些常量,比如常见的「Debug 日志开关」,我们一般都是在日志类通过 BuildConfig.DEBUG 来获取包状态,从而设置是否要打印出日志。

题外话

这里特别提一下为什么要用 Maven 这种方式,实际上单纯的抽离模块可以通过子模组的方式,Git 也有 submodule 这样的子模组管理方法,但用 Git 管理子模组会有很多问题,比如项目引用子模组的指针问题,在一个并行开发团队中,子模组指针往往会导致很多出人意料的问题,以后我会专门的在这方面写一篇博客做一个解析。

通过把子模块上传至 Maven 库有很多好处,比如导入起来很方便,只需要在配置文件中 compile 即可,而且开发该模块的时候只需要单独打开该子模组的代码,不像通过 Git 管理的依赖子模组,即使你只是为了修改子模组代码,也需要打开原来的完整项目,然后在项目下的子 module 进行开发,最后子模组代码和主项目代码得同时提交。

compile 'com.github.bumptech.glide:okhttp-integration:1.4.0'

另外它还有一些安全性的好处。通过这种方式,实际上也是一种对代码的保护,客户端开发人员不会轻易的修改这部分代码。

具体如何通过 Android studio 构建 maven 库,请移步 Gradle实战:发布aar包到maven仓库

具体问题

我把项目中的一些基础服务专门抽离了出来,其中就包括了一些跟 Log 日志打印相关的代码,原来项目中在build.gradle 中的 buildTypes 中设置了 DEVELOP_MODE 常量,来控制在不同渠道打包下的 Log 开关。

buildTypes {        debug {            // log日志开关            buildConfigField("boolean", "DEVELOP_MODE", "true")            }        release{            buildConfigField("boolean", "DEVELOP_MODE", "false")        }

然后,在具体的日志类中调用,动态获取 DEVELOP_MODE

public class DEBUG {    public final static boolean DEVELOP_MODE = BuildConfig.DEVELOP_MODE;}

现在,当我把这部分代码单独抽离出来到名叫「middleWare」的子 library 后,即使我仍然可以在该 library 中的 build.gradle 文件设置上述的 buildTypes 代码,但通过 maven 编译出来的 aar 包只能是 release 版本,自然也无法获取到那些动态配置的常量值。

所以,只能通过获取引入项目的 BuildConfig 类来获取了,所以我们自然的想到了用反射。下面是具体代码,注释也比较详细:

public class BuildConfigProvider {    private static Context sContext;    private static String packageName;    /**     * 通过反射获取ApplicationContext     *     * @return     */    private static Context getContext() {        if (sContext == null) {            try {                final Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");                final Method currentActivityThread = activityThreadClass.getDeclaredMethod("currentActivityThread");                final Object activityThread = currentActivityThread.invoke(null);                final Method getApplication = activityThreadClass.getDeclaredMethod("getApplication");                final Application application = (Application) getApplication.invoke(activityThread);                sContext = application.getApplicationContext();            } catch (Exception e) {                e.printStackTrace();            }        }        return sContext;    }    /**     * 通过反射获取包名     *     * @return     */    private static String getPackageName() {        if (packageName == null) {            try {                final Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");                final Method currentPackageName = activityThreadClass.getDeclaredMethod("currentPackageName");                packageName = (String) currentPackageName.invoke(null);            } catch (Exception e) {                packageName = getContext().getPackageName();            }        }        return packageName;    }    /**     * 获取具体的域值     *     * @return     */    public static Object getBuildConfigValue(String fieldName) {        try {            Class<?> clazz = Class.forName(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();        } catch (IndexOutOfBoundsException e) {            e.printStackTrace();        }        return "";    }}

这里实际上可以用一个方法获取 context 然后就直接可以拿到 packageName,为了看的清晰,所以分成两个方法了。

然后把之前那个 DEBUG 类适当改动下,将 DEBUG 类放在该子模块代码中:

    public final static boolean DEVELOP_MODE = isDevelopMode();    static boolean isDevelopMode(){        return (boolean)BuildConfigProvider.getBuildConfigValue("DEVELOP_MODE");    }}

这样只需要在引入项目中的 buildTypes 中设置 DEVELOP_MODE 的各种配置就能在项目中动态的调用日志开关了。

比如我们项目中的日志打印类 Glog.class,每个日志等级的打印前都会有 DEBUG.DEVELOP_MODE 的判断:

public class GLog {    public static void d(String message) {        if(TextUtils.isEmpty(message)){            return;        }        //判断日志开关        if (DEBUG.DEVELOP_MODE) {            final StackTraceElement[] stack = new Throwable().getStackTrace();            final int i = 1;            final StackTraceElement ste = stack[i];            Log.println(Log.DEBUG, LOG_TAG, String.format("[%s][%s][%s]%s", ste.getFileName(), ste.getMethodName(), ste.getLineNumber(), message));        }    }}

这里只是通过打印日志的例子来展示如何在 aar 中调用主项目的 BuildConfig 类获取编译类型,其他各种 BuildConfig 中的域都可以用这种方式获取到

0 0