long long ago,android开发还只能在eclipse环境中进行开发,如果遇到多产品发布的需求,唯一的选择就是把工程项目拷贝一份出来,然后定制修改后进行打包发布。如果是深度定制的还好,若只是修改logo或应用名称的这种场景,再进行项目的开发就需要在所有产品的项目工程里进行重复性的调整,可怕。
而如今,我们有了更成熟的方案,只需要在guild.gradle文件中进行简单的配置,就可以实现一个项目打包多个产品的目的,果真是逆水行舟,不进则退。
注:这里的“产品”特指对客户进行定制化开发,类似于多渠道发布。
调整build.gradle
在gradle构建的android工程里,要实现多产品发布,首先要在module的build.gradle文件中声明所有的产品名称:
android {
...
productFlavors {
productA {
//产品A的配置
}
productB {
//产品B的配置
}
//C/D/E/F...
}
}
配置产品参数
在某个product下可以指定该产品的一些特定参数,若省缺则会使用defaultConfig中的定义。
- applicationId 应用id,也就是包名,这里的包名会覆盖掉defaultConfig中的applicationId。
- applicationIdSuffix 包名后缀,顾名思义这是指定包名后的后缀,会把组合后的字符串作为新的包名,可以和applicationId组合使用,如果产品没有定义applicationId,则会和defaultConfig中的applicationId进行组合生成新的包名。
- versionName 指定产品versionName,会覆盖掉defaultConfig中的versionName
- versionNameSuffix versionName后缀。同applicationIdSuffix
- versionCode 指定产品versionCode,会覆盖掉defaultConfig中的versionCode
- manifestPlaceholders 指定产品manifestPlaceholders,会覆盖掉defaultConfig中的manifestPlaceholders,通常用在重新指定产品包名造成需要多个第三方SDK-key的场景。
-
buildConfigField 指定buildConfigField,用来在编译阶段定义一些常量,可以定义多个,每行的定义格式为:
buildConfigField “类型” “变量名” “变量值”
。此处需要注意,string类型的常量值需要写入引号,用单引号包裹。 - signingConfig 指定产品的签名配置。会被buildTypes覆盖。
android {
...
productA {//新的包名为com.nightfarmer.demo.A.M
applicationId "com.nightfarmer.demo.A"
applicationIdSuffix ".M"
versionName "2.0.1"
versionCode 35
manifestPlaceholders = [
JPUSH_APPKEY : "e8f83a857defbf8760fe11111"
]
buildConfigField "String", "SERVER_HOST", '"http://www.pa.com"'
signingConfig signingConfigs.release
}
productB {//新的包名为com.nightfarmer.demo.B.N
applicationId "com.nightfarmer.demo.B"
applicationIdSuffix ".N"
versionName "3.0.2"
versionCode 28
manifestPlaceholders = [
JPUSH_APPKEY : "e8f83a857defbf8760fe22222"
]
buildConfigField "String", "SERVER_HOST", '"http://www.pb.com"'
signingConfig signingConfigs.release
}
}
获取产品参数
在编译阶段,product中的配置会被写入BuildConfig和AndroidManifest.xml中。
signingConfig 配置用于打包签名
manifestPlaceholders 中的键值对会替换AndroidManifest.xml中${key}对应的文本
其他配置则会写入BuildConfig的常量中,如下:
BuildConfig.APPLICATION_ID
BuildConfig.VERSION_NAME
BuildConfig.VERSION_CODE
BuildConfig.DEBUG
BuildConfig.SERVER_HOST
BuildConfig.BUILD_TYPE
BuildConfig.FLAVOR
切换构建类型
在AS左下方,BuildVariants视图中可以切换module的构建类型,若找不到可以双击shift然后输入BuildVariants快速打开。
productFlavors和buildTypes中的配置会进行多对多组合,组合结果会在BuildVariants展示供选择。
buildTypes中的配置会覆盖productFlavors中的配置,相同配置的优先级如下:
buildTypes > productFlavors > defaultConfig
代码资源文件的多产品配置
回到开篇的需求,新产品需要定制开发一些功能,但是其余大部分代码仍然和公用版保持同步更新,这种场景就需要我们为新产品提供一个独立的工程空间以供额外开发使用,不但可以使用公共代码且不影响公用版本打包。
使用productFlavors来控制多产品之后,产品代码管理也会变得非常的便捷。
默认情况下在project类型视图中的工程结构是这样的:
-------------
src
丨----androidTest
丨----test
丨----main
|----java
|----res
|----AndroidManifest.xml
假设我们现在创建了productA和productB,且需要对这两个产品进行部分定制化开发,我们只需要在src下创建和产品同名的文件夹即可:
-------------
src
丨----androidTest
丨----test
丨----main
|----java
|----res
|----AndroidManifest.xml
丨----productA
|----java
|----res
|----AndroidManifest.xml
丨----productB
|----java
|----res
|----AndroidManifest.xml
注意,java/res/和AndroidManifest.xml不是全部必需的,如果只是更改logo等图片资源,则只需要res/draweble。同理如果只扩展部分代码,则只需要java文件即可。再同理,如果需要声明一些额外的组件和权限,则新增AndroidManifest.xml进行调整。
在BuildVariants中切换相应产品即可激活对应目录中的工程结构。
依赖的多产品配置
继续我们的需求,如果产品扩展部分使用了一些依赖,而这些依赖我们并不希望被打包进公共版本和其他产品版本,我们只需要把依赖使用的compile关键字调整为产品对应的关键字xxxCompile
即可:
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
//...
compile 'com.android.support.constraint:constraint-layout:1.0.0-beta4'
//产品A使用gson进行序列化
productACompile 'com.google.code.gson:gson:2.8.1'
//产品B使用jackson进行序列化
productB服务器托管网Compile 'com.fasterxml.jackson.core:jackson-core:2.7.3'
productBCompile 'com.fasterxml.jackson.core:jackson-annotations:2.7.3'
productBCompile 'com.fasterxml.jackso服务器托管网n.core:jackson-databind:2.7.3'
}
这样产品各自的依赖直接是互不影响的。
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net