开发中需要根据不同的用户或者场景,采用不同的逻辑/效果,生成不同的包,但是大部分代码是不变的。如果同时维护两个大致相同的项目,工作会既枯燥又毫无用处,还浪费时间。这时候就该用到gradle的动态编译了。
最近有个项目app,要求可以切换角色,切换之后,基本上一半的字段名称都要改变,后台接口返回的内容有可能也会不一样,还没想到怎么做....感觉这种动态编译也不能实现,各位大虾有什么好办法么?
一、配置gradle
build.gradle中可以包括两个节点:buildTypes和productFlavors
-
buildTypes默认有release和debug两个选项。
-
我们这里在productFlavors增加Seller和buyer。(假设买家和卖家两种场景)
productFlavors{ buyer{ applicationIdSuffix ".buyer" } Seller{ applicationIdSuffix ".Seller" } }
buildTypes和productFlavors组合就有下面4个版本了。
SellerDebug
SellerRelease
buyerDebug
buyerRelease
二、新建项目文件,与src下新建Seller, buyer两个文件夹,并分别创建包名,与相同的类(方法名相同,方法体不同)。如下
这时,只能识别一个buyer,另一个识别不了,没关系,这是在gradle中顺序,默认只编译第一个。在打包时可以选择编译哪个。
三、在mian项目中使用这个方法。
四、为了区分两个包,把apk名改一下。
//修改生成的apk名字
applicationVariants.all {
variant ->
variant.outputs.each {
output ->
def oldFile = output.outputFile
if (oldFile.name.contains('.apk')){
def newName = variant.applicationId+'-v' + defaultConfig.versionName + '-'+variant.buildType.name+'.apk'
output.outputFile = new File(oldFile.parent, newName)
}
if (output.zipAlign != null) {
output.zipAlign.doLast {
output.zipAlign.inputFile.delete()
}
}
}
}
五、打包。
如果想动态修改minifest.xml里的应用名和图标,可以在productFlavors中修改,在minifest.xml中使用。
productFlavors{
buyer {
applicationIdSuffix ".buyer"
manifestPlaceholders = [
app_name: "淘宝买家端",
app_icon: "@mipmap/icon_launcher_buyer"]
}
seller {
applicationIdSuffix ".seller"
manifestPlaceholders = [
app_name: "淘宝卖家端",
app_icon: "@mipmap/icon_launcher_seller"]
}
}
<application
android:allowBackup="true"
android:icon="${app_icon}"
android:label="${app_name}"
android:supportsRtl="true"
android:theme="@style/AppTheme">
最后介绍下,动态应用名。有时候需要根据选择的productFlavor和buildType来生成不同的应用名,防止调试、测试时搞混。
def appType;
def appName;
android {
signingConfigs {
config {
keyAlias KEY_ALIAS
keyPassword KEY_PASSWORD
storeFile file('../app/tong_key.jks')
storePassword KEYSTORE_PASSWORD
}
}
compileSdkVersion 25
buildToolsVersion "25.0.3"
defaultConfig {
applicationId "com.lemon.studykit"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
appType="正式"
debuggable false
buildConfigField("String", "generalHost", "\"http://192.168.1.224:8089/\"")
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.config
}
debug {
appType="开发"
buildConfigField("String", "generalHost", "\"http://192.168.1.224:10001/\"")
signingConfig signingConfigs.config
}
inerTest {
appType="内测"
buildConfigField("String", "generalHost", "\"http://192.168.1.69:10001/\"")
debuggable true
jniDebuggable false
signingConfig signingConfigs.config
minifyEnabled false
zipAlignEnabled true
}
}
productFlavors {
apple {
appName="苹果公司"
}
lemon {
appName="柠檬公司"
}
}
productFlavors.all { flavor ->
flavor.manifestPlaceholders = [
app_name: "${appName}-${appType}",
app_icon: "@mipmap/ic_launcher",
app_icon_round: "@mipmap/ic_launcher_round"
]
}
lintOptions {
checkReleaseBuilds false
abortOnError false
}
//修改生成的apk名字
applicationVariants.all {
variant ->
variant.outputs.each {
output ->
def oldFile = output.outputFile
if (oldFile.name.contains('.apk')){
def newName = variant.applicationId+'-v' + defaultConfig.versionName + '-'+variant.buildType.name+'.apk'
output.outputFile = new File(oldFile.parent, newName)
}
if (output.zipAlign != null) {
output.zipAlign.doLast {
output.zipAlign.inputFile.delete()
}
}
}
}
//如果你的as是3.0以后的,outputFile就不能直接替换了,改为以下写法
applicationVariants.all { variant ->
variant.outputs.all { output -> // each 改为 all
def newName = variant.applicationId+'-v' + defaultConfig.versionName + '-'+variant.buildType.name+'.apk'
def outFile = output.outputFile
if (outFile != null && outFile.name.endsWith('.apk')) {
outputFileName = newName
}
}
}
}