-
简介
智能家居APP出海版本已启动开发,由于出海版本维护周期较长,在国内Master分支的基础上,为海外版本拉取单独的分支,会额外增加开发和维护成本,影响正常的开发进度。
-
需求分析
同一个工程,通过差异化的设计编码,构建出两套差异化的版本,实现在同一个工程下管理不同的版本的目的。
其中,差异化版本之间,存在以下异同点:
- 不同版本之间,大部分代码相同,公用一套公共组件,底层代码等;
- 不同版本之间,需要差异化实现不同的功能,包括显示(xml)不同,逻辑(java)不同,配置(Manifest)不同等;
- 不同版本之间,包名不同;
-
方案描述
在Android Studio中,通过配置不同的productFlavors实现同一个工程下的差异化版本构建。例如,通过同一套代码,实现两个不同的产品,分别为productA和productB,具体的操作如下。
-
build配置
在build中分别为productA和productB配置不同的flavors,如下:
android {
compileSdkVersion 24
buildToolsVersion "24.0.2"
defaultConfig {
applicationId "com.example.product"
minSdkVersion 20
targetSdkVersion 24
versionCode 1
versionName "1.0.0.0"
}
productFlavors {
productA {
applicationId "com.example.product.a"
versionName "1.0.0.1"
}
productB {
applicationId "com.example.product.b"
versionName "1.0.0.2"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile(‘proguard-android.txt‘), ‘proguard-rules.pro‘
}
}
}
其中,不同flavors下面设定的applicationId即为对应版本的进程名称,也即package name。
Tips:Android工程中build中设定的applicationId和Manifest中设置的package(name)有什么区别?
解释:application id与package name在Android工程中分工明确,其中:
? application id 负责 App 的进程 ID
? package name 负责 R 的包名以及 Manifest 中 Activity 等四大组件的相对包名
如果 build.gradle 中没有指定 applicationId,那么 application id 的默认值就是 manifest 的 package 属性值。
-
工程结构
在src/main目录下新建两个同级目录productA与productB,目录的名称要与productFlavors中设定的工程名保持一致。如下所示:
productA/productB与main目录一样,也可以有自己的java包,res资源文件和AndroidManifest配置文件。其中,对于productA和productB来说,main目录下的文件和资源是共享的,而productA与productB下的文件和资源是对应的product特有的,在这里可以做一些差异化的编码,达到共主线,差异化逻辑的效果。
值得注意的是,productA和productB中可以存在同名文件,在gradle编译的时候,会自动链接各自product的文件。这样就给编码带来了极大的便利。例如:
- 想要做到差异化显示,只需要在对应的product目录给同一个Activity配置不同的同名xml;
- 想要实现不同的页面逻辑,只需要在对应的product目录中实现各自的同名Activitry;
- 想要获取差异化数据,只需要在对应的product目录中配置不同内容的同名的Config;
- 想要对同一个Activity实现不同的配置(启动模式,过滤模式等),只需要在对应的product中配置不同的Manifest;
- 想要在不同版本中依赖不同的Module或jar包,也可以通过差异化的依赖来实现,如下:
dependencies {
compile project(‘:common-lib‘)
productACompile project(‘:common-entity‘)
productBCompile project(‘:common-overseas-entity‘)
}
- 想要在Manifest中配置不同的渠道值,只需要在productFlavors中配置不同的manifestPlaceholders,如下:
productFlavors{
productA{
manifestPlaceholders = [CHANNEL:"productA"]
}
productB{
manifestPlaceholders = [CHANNEL:"productB"]
}
}
对应的Manifest配置如下:
<meta-data android:name="UMENG_CHANNEL" android:value="${CHANNEL}"/>
类似这样的操作,可以在多渠道差异化打包过程中,减少了很多不必要的逻辑判断。这样一来,不仅代码更加健壮,而且代码可读性大大提升。
-
编译命令
代码编写完成之后,就可以通过gradle编译出差异化的版本。与一般的编译情况一样,差异化编译版本也有两种编译途径:
- 通过gradle视图,直接点击编译;
如下:
分别点击assembleProductA和assembleProductB就可以差异化的编译出productA和productB的包;
- 通过命令行编译;
以编译ProductB为例,
- gradlew assembleProductB:编译productB的release和debug包;
- gradlew assembleProductBDebug:编译productB的debug包;
- gradlew assembleProductBRelease:编译productB的release包;
-
运行
编译之后,就可以生成可执行的二进制文件,如下:
分别安装app-productA-debug.apk和app-productB-debug.apk,可以发现手机上生成了两个不一样的apk,如下:
这是因为,二者的keystore虽然一致,但是不同的product的applicationId不一致,所以对应的签名信息是有区别的。所以,前后安装两个APK不会覆盖。
分别点击进行两个APK,跳转的流程如下:
可以发现,通过上述方法已经实现了共主线差异打包的能力。
-
参考文献
- http://www.jianshu.com/p/81eff804d1b8
- http://www.jianshu.com/p/ceb354f41f0e
- http://www.jianshu.com/p/4677efee7214
- http://blog.csdn.net/crazyman2010/article/details/53471162
- http://www.jianshu.com/p/1ae5c85d2ff2
原文地址:https://www.cnblogs.com/charles04/p/9017501.html