android 一套代码多用 以及 多套代码用于一个项目

5,281 阅读5分钟

文章关键字 productFlavors

目前在项目中遇到了这样一种情况,公司的产品需要在不同的机子(自己产品)上进行运行,有的是正常手机 有的是没有显示屏的手机,需要另外做处理。那么现在问题来了,总不可能一个产品一个项目把,那么我们就可以通过productflavors进行代码多用

项目使用mvp架构 demo也是以此为前提

第一种情况,代码不变,素材变化

举一个极端的例子,你家的app卖不出,别人来代理你家的app,说图标要换成他家的,那么你怎么办?总不可能直接拿项目改把,万一又说不要你家app了呢?(开个玩笑)

步骤: 先将android studio的目录结构改成project

image.png

在与main同级下新建一个目录 我这里叫seller

image.png
并且根据main目录的目录结构(一定要一样),新建res 新建values 新建strings.xml
image.png
并将原来的appname 在后面加上111

tips1:这里说明一下,在res目录下的替换都是批量替换,在main目录的strings.xml里面肯定不止一个strings,我们在seller的strings.xml下新建一个appname 并更改了值 那么只有这个appname会被替换 其他的还是原封不动的使用main的东西 tips2:其他同理,只要是在res目录下,都是批量替换(名字一定要一样 无论是string 还是图片)

在替换之前 我们还需要做一些事情,就是声明 在gradle文件里面

image.png
新增一个productFlavors 里面声明一个seller

 productFlavors {
        seller {
        }
    }

gradle sync之后 在build Variants里面就可以看到不同的项目了

image.png

image.png

你可能会说 现在不就只剩一个了么,想用原来的代码不想用seller怎么办? 笑哭.jpg 新增一个就好

image.png
新增一个空的origin

image.png
声明一下
image.png

打包的时候你可以同时打两个包

image.png

image.png

在build Variants里面的选项的作用:你选择哪个,运行的时候(debug run)就运行哪个版本 以上就是素材的替换

第二种情况代码的替换

可能某一个部分的机器需要另外的新增的代码 而且与原来的代码区别还是蛮大的 那么我们可以进行代码的替换

tips1:代码的替换并不是部分替换 而是文件的替换(例如一个mainActivity的替换,而不是mainActivity的某个代码片段的替换)

tips2:要替换的代码的那个文件不能存在于main文件夹内

现在 我们在seller下新建一样的代码结构

image.png
并把MainActivity文件复制过来

image.png
并将Build Variant设置成sellerdebug

image.png
你会发现报错 所以说替换代码的时候main 文件夹内不能存在那个文件

现在将origin也复制一遍代码结构 并且将main文件夹内的删除

image.png
不再报错

Tips:目前Build Variant是sellerdebug 所以seller下面的文件夹和main文件夹是有颜色的 但是origin没有,侧面说明android studio还是挺智能的

以上就是代码的替换 只要你你运行那个分支你就会运行哪里的代码(没有替换的代码会用main文件夹的)

一些使用心得:如果只是小部分代码需要替换 最后还是在main里面if else修改 比较方便 不然你就要维护两套代码 使用mvp分层的话 可以尽量减少文件的替换 维护更少的代码!!!

第一二种情况可以混用

字符串的替换

如果你在seller中使用一个ip origin使用一个ip 怎么办

productFlavors {
        seller {
            buildConfigField("String", "URL", '"www.baidu.com"')
        }
        origin{
            buildConfigField("String", "URL", '"www.google.com"')
        }
    }

使用buildConfig字段

String ip = BuildConfig.URL;

这样这个ip在seller下是baidu 在origin下是google 是自动的

此外 也可以在debugrelease下使用

buildTypes {
        debug{
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            buildConfigField("String", "URL", '"www.baidu.com"')
        }
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            buildConfigField("String", "URL", '"www.google.com"')
        }
    }

项目的判断

if (BuildConfig.FLAVOR.equals("seller")) {
            //// TODO: 2017/12/7  
        }

使用flavor字段可以判断运行的是哪个分支 然后进行小范围的代码的if else

项目的compile

例如 seller下使用腾讯的sdk 但是origin的使用百度的sdk 难道打包就需要打包两个sdk???

image.png

举个例子 使用分支的名字加上Compile就可以只在seller项目中compile这个东东

但是这样有个问题 如果你在同一套代码里面做了if else判断 如果在某个分支里面没有compile这个包 那么可能会报错

//举个例子:demo例子
//如果在seller项目中没有compile tx的sdk 那么编译的时候会报错 说没有找到tx sdk这个类
if(flag){
  TXSdk.init(this)
}else{
  BaiduSdk,init(this)
}

ui一样的情况下 新增代码逻辑

在我的项目中 有一台手机是没有屏幕的 但是有一个lcd屏 所以我需要新增逻辑 进行处理 假设这个没有屏幕的手机是seller项目

seller项目需要compile一个jar包这个jar包很大 因为我是sellerCompile的 在origin中是没有的 所以我不能在main的代码中写入关于这个jar的代码 不然origin就编译不起来

那么我是怎么办的呢?

image.png

我新增一个receiver 和一个service 通过发intent的方式 如果是seller项目自然可以收到intent 并且使用jar包的类进行处理(使用jar包的代码在seller分支里面 而不是在main里面) 就没有问题,如果是origin项目 不会有receiver会收到这个intent 然后就不会处理

所以我是通过receiver进行中转处理的

以上就是我在项目中遇到的一些问题 以及productFlavor的一些使用 当然 productFlavor还有其他的一些用法 大家可以自己去了解一下

项目的demo(只有结构哈):https://github.com/Lemniscate317/ProductFlavorsDemo