利用Gradle的productFlavors使用应用多现场配置

由于公司的性质,做一个app(产品)需要销售到不同的现场(项目)使用,不同的现场有不同的差异化配置,我们不可能为每个现场的app维护一套代码,如果这样的话,假如有20个现场就得维护20份代码…

问题: 有什么解决办法呢?

  1. 在以前的项目中,有一种最简单粗暴的办法,就是在代码里面进行
  if(XX现场){
     执行逻辑A
  }else if(XX现场){
     执行逻辑B
  }

这种办法特点就是简单直观,但是有个明显的缺点,判断逻辑太多,导致代码臃肿,假如增加多几个现场,就得加多几个if()else(),最后导致项目可维护性很差.

2 定义一个通过的接口,然后不同现场去定义一个实现类,具体去实现具体的逻辑。

interface ILoginLogic{
     void login();
     void checkOutPwd();
}

public class ALoginIml implements ILoginLogic{
    @Override
    public void login(){
       //实现A现场的登录逻辑
    }
    @Override
    public void checkOutPwd(){
       //实现A现场的检查密码逻辑
    }
}

public class BLoginIml implements ILoginLogic{
    @Override
    public void login(){
       //实现B现场的登录逻辑
    }
    @Override
    public void checkOutPwd(){
       //实现B现场的检查密码逻辑
    }
}

这种做法的优点就是把逻辑提取出来,通过接口实现的办法使得代码可阅读性提高,更易维护。但是缺点就是需要增加更多的类,并且每个页面都要定义不同的接口和实现,并不能实质性地改善问题..

3 在无意中发现,Gradle提供了一种多渠道多版本管理的工具–priductFlavors
productFlavors顾名思义,就是用于定义产品的特性,这是每个产品不同的地方。有了它我们就可以用一套代码创建不同的产品。接下来我们看下如何使用…

由于已经集成在gradle中,所以能直接在gradle中使用,在app的build.gradle中创建productFlavors结构

android{
    #......
    productFlavors{
        productA{
            #这里定义产品A的特性
        }

        productB{
            #这里定义产品B的特性
        }

        #更多产品 ...
    }

进行编译,在Build Variants版块里面我们能看到生成出来的不同Build Variant
这里写图片描述
这里切换不同的product能够切换到不同的产品上面去。

  • 那么怎么样才能在不同产品上体现出差异化呢??
    肯定是在对应的product括号下添加对应的属性,我们看下写法..

productA{
buildConfigField ‘String’, ‘HOST’, ‘”http://192.168.0.208:7001/“’
}

productB{
buildConfigField ‘String’, ‘HOST’, ‘”http://192.168.0.30:7001/“’
}

首先我们添加一个名为HOST的字符串对象,实现编译, 然后我们在app的build/generated/buildConfig/productA(由于当前选的是productA项目)/包名/下有个BuildConfig.java的文件,打开看下
这里写图片描述
首先我们可以看到这个文件是自动生成的且无法修改的,可以看到文件里面有DEBUG,AOOLICATION_ID这些参数,这些都是默认有的,我们看重点
这里写图片描述
这不就是我们在productA里面声明的HOST参数吗,系统帮我们声明了一个名为HOST的String对象,那么在Activity里面怎么使用它呢,很简单,只要BuildConfig.HOST就可以拿到HOST对象了。

由于我们现在是在productA项目下,我们在Build Variants里面将现场切换成ProductB试一下。然后我们在刚才Activity声明的HOST变量 点进去看一下,发现跳到了ProductB的BuildConfig.java文件来了
这里写图片描述
很显然,HOST的对象已经变了,变成了productB的对象值。

此外,除了String对象,我们还可以定义其他不同的对象,比如boolean,Class对象等等,

 buildConfigField 'boolean', 'displayFamilyName', 'true'  //列表Item前面是显示姓还是名
  buildConfigField 'Class', 'scheduleAddr', 'cn.com.minstone.httplogic.schedule.addr.PASys.class'

都是能够生成出来的。

  • 替换manifest字段
    在mainfest里按照一定格式自定义个可变的字段,在gradle里根据不同版本赋予不同的值.
    注意:自定义mainfest字段的格式为:
${ YOURNAME };例如${APP_NAME}

具体写法是

productA{ 
   manifestPlaceholders = ["APP_KEY": "123456789",]
}

在manifest文件里面可以这么引用

<meta-data
   android:name = "APP_KEY"
   android:value = "${APP_KEY}"
>
</meta-data>
  • 定义res对象
    我们还可以定义资源对象,具体用法
productA{
  resValue "string", "appName", '"柳州数字质监移动办公"'
}

然后在strings.xml文件里面使用

<resources>
    <string name="app_name">@string/appName</string>`
</resource>

此外,我们还可以定义像versionCode,versionName这样的字段,这里我就不一一类出来了。

假如所有现场都有一个统一的变量,这时候我总不能每个product里面都申明一模一样的变量吧??放心,这个问题productFlavors也帮我们考虑了,我们可以定义一个叫跟productX同级的defaultConfig的标签,标签里面可以放所有现场共用的属性和变量,具体操作是

android{
    defaultConfig{
        //存放公共变量
        buildConfigField 'String', 'COMMON', '"admin"'
    }
    productA{
      ....
    }
    productB{
      ...
    }
}

这样的话在productA和productB项目里都可以用到COMMON变量,假如productA的COMMON变量跟其他现场不一样怎么办?可以在productA标签下重写该变量进行差异化区分。

 productA{
 buildConfigField 'String', 'COMMON', '"aaaa"'
 }

通过productFlavors,我们可以很方便地对每个现场的变量进行控制,只需要鼠标点击只能切换到对应的项目,并且变量的值也能够对应切换,这样我们就能够去掉恶心的if else语句,可维护性更高。

最后,我说下我根据自己项目特点使用productFlavors的一些小技巧。

  1. 首先,随着项目的增大,你会发现每个标签下的变量越来越多,这样的话会导致app的build.gradle文件的行数会越来越多,影响可阅读性。所以,我将不同现场的标签抽取出来,分成个个文件,然后在app的build.gradle引用这些文件
    这里写图片描述

这样的话显得更加的直观 结构更加清晰,并且减少了build.gradle的代码量

2.假如我一个现场的主页面要导航页的5个功能,另外一个现场只要其中的4个功能,导致功能性的差异,这时候使用productFlavors怎么做?
这里我提供一种解决思路,也是使用String变量来存,但是存放的值是Json字符串

            buildConfigField 'String', 'workBenchMenu', '"[{\\"title\\": \\"所有公文\\",\\"icon\\": \\"workbench_review\\"},{\\"title\\": \\"消息\\",\\"icon\\": \\"workben_message\\"},{\\"title\\": \\"任务\\",\\"icon\\": \\"workben_task\\" },{\\"title\\": \\"联系人\\",\\"icon\\": \\"workben_contact\\"},{\\"title\\": \\"单位动态\\",\\"icon\\": \\"workbench_dynamic\\"},{\\"title\\": \\"行程\\",\\"icon\\": \\"workben_schedule\\"},{\\"title\\": \\"公文分类\\",\\"icon\\": \\"workbench_documentrank\\"}]"'

然后Activity里面通过解析该json去生成布局,实现功能性差异。
当然还有其他解决思路,你可以自己思考下。。。

  • 7
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值