使用productFlavors配置项目移植

概述

有时候需要做两个或多个项目,但都用的同一套代码.只有稍微的一些布局或者代码的改动.
我们常规的做法是再切一个分支,再在这个分支上做相应的改动.但比如发现了某一处bug,或者需要统一改个需求.那我们就需要在每一个分支上都进行这种变动.
如果项目多的话会很不好维护.下面就介绍怎样通过productFlavors的方式配置项目移植.

Flavor

在主项目build.gradle中配置productFlavors

android{
    ...
    defaultConfig{
    ...
    }
    productFlavors{
        jkxt {
            applicationId "com.****.****"
            buildConfigField "String", "PROJECT_SIGN", "\"jkxt\""
            manifestPlaceholders = [BAIDU_CHANNEL_VALUE       : "*****",
                                    PACKAGE_NAME              : "*****"]
        }
        jkhd {
            applicationId "com.****.****"
            buildConfigField "String", "PROJECT_SIGN", "\"jkhd\""
            manifestPlaceholders = [BAIDU_CHANNEL_VALUE       : "*****",
                                    PACKAGE_NAME              : "*****"]
        }
    }
}

上面定义了一个productFlavors,gradle会为这个flavor关联对应的sourceSet,默认位置为src/目录,对应到本例就是src/jkhd,如果没有建文件夹,则默认为src/main.看如下解释

#####The product flavors support the same properties as defaultConfig—this is because defaultConfig actually belongs to the ProductFlavor class. This means you can provide the base configuration for all flavors in the defaultConfig {} block, and each flavor can override any of these default values, such as the applicationId.

也就是说,defaultConfig中可以配置的属性,比如applicationId,minSdkVersion等,都可以在productFlavors中配置,因为defaultConfig就是一个productFlavor实例.

在本例中,解释上面两个属性,buildConfigField可以理解为定义一个常量,传入的值分别代表type,name,value;
通过BuildConfig.PROJECT_SIGN 可以拿到相应的值,比如我们熟悉的BuildConfig.DEBUG,就是系统定义的一个常量.

manifestPlaceholders作用是动态替换manifest文件,传入的是一个map对象,写法如上所示.在配置多个项目时,一些第三方的key比如友盟,极光等需要进行动态配置,就需要用到这个属性,在manifest文件中把需要动态配置的属性按如下写法,android:name=”${PACKAGE_NAME}”

替换资源文件

上面讲到productFlavors已经为我们关联了对应的sourceSet,所以我们只需要把不同的资源文件放入相应目录下
以jkhd为例,在src/jkhd目录下新建res文件,新建需要替换的资源文件夹,比如需要替换app_name
只需要在src/jkhd/res/values/string.xml,新建app_name标签即可.其他公用的资源不需要添加,找不到的话会默认从主项目下面找.

使用第三方sdk

做某些项目可能用用到不用的第三方sdk,但其他项目并不需要这个sdk,那么怎么为特定的项目添加sdk呢?

android {
productFlavors {
    jkhd {
        }
    }
}
...
dependencies {
    jkhdCompile 'com.nineoldandroids:library:2.4.0'
}

然后通过反射的方法,进行具体判断

class MyActivity extends Activity {
private boolean useSdk;

@override
public void onCreate(Bundle savedInstanceState) {
    try {
        Class.forName("com.nineoldandroids.......");
        useSdk = true;
    } catch (ClassNotFoundException ignored) {
        }
    }
}

动态替换代码

  1. 如果在src/jkhd目录下新建同名类的话会报类重复的问题.但我们可以新建src/jkhd,和src/jkxt两个文件夹,在这两个文件夹中同时写入一个与主目录不同的类,在主目录中进行调用,这样是没有问题的
  2. 直接在主目录中以判断标记位的方法来达到动态替换的效果.

总结

productFlavors对于配置项目移植,和多渠道打包都非常方便,节省了我们大量的工作.目前所介绍的配置基本上可以满足我们的需求.以后再也不用担心多渠道打包和项目移植啦~

欢迎大家提出更多新的用法!

参考资料
Product-flavors
美团Android自动化之旅—适配渠道包