android build type,Android应用构建-BuildType ProductFlavor

2023-05-16

个人原创,欢迎指正

场景:

用同一套核心代码来维护多个订制的app

现开发出一套Android app, 在此app基础上,复制出另一个app, 两个app之间略微有一些不同之处。

将不同环境的APP安装在同一设备中。

使用Gradle构建的优点:

提高效率,产品未成熟,包括需求上的修改及各种BUG,用一套代码来维护,可以减少不必要的重复劳动

免除传统的重复修改环境,打包,安装繁琐的流程,期间漏改在所难免。而使用Gradle构建,只需选择环境-安装。快捷,方便,不出错。

实现需求:

两个APP, 用一套代码来维护,不同之处在于应用名称,图标,包名,部分跳转逻辑,部分页面,部分页面显示文字。

三个环境: 开发, 测试, 生产, 每个环境的版本,版本号,图标不同

命名规则:ProductFlavor_产品版本号_日期_BuildType.apk

whgc_1.0.0_20190624_Dev.apk

whgc_1.0.0_20190624_Test.apk

whgc_1.0.0_20190624_Release.apk

各环境APP可安装在同一手机

环境

AndroidStudio 3.4

Gradle插件:3.4.0

Gradle:5.1.1

三个环境 实现步骤:

新建项目

app: build.gradle

apply plugin: 'com.android.application'

android {

compileSdkVersion 28

defaultConfig {

applicationId "com.minicup.test"

minSdkVersion 19

targetSdkVersion 28

versionCode 1

versionName "1.0"

testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

}

buildTypes {

release {

minifyEnabled false

proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

}

}

...

}

app: build目录结构

905242b567e0

image.png

执行assemble任务

任务执行后在build目录中生成相应文件

905242b567e0

image.png

assemble任务会自动创建debug和release两个目录

这里的debug和release目录对应build.gradle中buildTypes的配置

可项目中buildTypes中明明只有release,并没有debug,原因是这里的release和debug是系统默认的两个构建类型,即使没有配置,系统依然会生成这两个目录

修改一下build.gradle,将release配置也删除,再次运行assemble任务,发现同样生成了release和debug两个目录

android {

buildTypes {

}

}

接下来在buildTypes中添加个dev 类型

android {

buildTypes {

release {

minifyEnabled false

proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

}

dev{

}

}

}

同步后首先看到变化如下:

905242b567e0

image.png

905242b567e0

image.png

再次执行assemble任务:

905242b567e0

image.png

以上符合预期。

自此在buildTypes中,我们可以配置三种环境,解决关于三个环境的需求

android {

...

buildTypes {

appDev{

minifyEnabled false

proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

}

appTest{

minifyEnabled false

proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

}

appRelease {

minifyEnabled false

proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

}

}

}

也可以这样配置

android {

...

buildTypes {

// 常用配置:

// signingConfig,

// buildConfigField,

// versionNameSuffix

// multiDexEnabled,

// zipAlignEnabled,

// applicationIdSuffix

debug{

minifyEnabled false

proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

}

appDev{

initWith(debug)

}

appTest{

initWith(debug)

}

appRelease {

initWith(debug)

}

}

}

assemble后的结果

905242b567e0

image.png

我们也可以打开ProjectStructure,在这里配置所有可以配置的东西

905242b567e0

image.png

assemble是构建所有buildTypes productFlavors嵌套配置生成的目录。

buildTypes中的配置命名不能以test开头, //BuildType names cannot start with 'test'

除了debug,其他构建类型都是release类型的,因此,在没有设置签名配置时,会生成含有unsigned的标志。

所有的module必须有同样的构建类型,即使是空的

为三个环境指定签名文件,及不同的BASE_URL

先生成jks文件,后配置build.gradle

android {

signingConfigs {

release {

storeFile file('app.jks')

storePassword '123456'

keyAlias = 'app'

keyPassword '123456'

}

}

...

buildTypes {

debug{

buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/debug\""

}

appDev{

buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/appDev\""

signingConfig signingConfigs.release

}

appTest{

buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/appDev\""

signingConfig signingConfigs.release

}

appRelease {

buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/appRelease\""

signingConfig signingConfigs.release

}

}

}

编译后,生成相应的BuildConfig,里面的内容与我们配置的一致

905242b567e0

image.png

运行APP

905242b567e0

image.png

EventLog

11:07 Executing tasks: [:app:assembleDebug]

11:07 Gradle build finished in 4 s 175 ms

11:07 Install successful

默认运行app时,执行的是assembleDebug任务。

通过设置BuildVariants来切换任务。

905242b567e0

image.png

切换为appDev构建类型后运行app的效果:

905242b567e0

image.png

EventLog

11:19 Executing tasks: [:app:assembleAppDev]

11:19 Gradle build finished in 6 s 488 ms

11:19 Install successful

对应的构建类型BuildConfig中生成了不同的值,运行 appTest, appRelease也得到相应的结果。

但在运行APP时出现一个问题,也是上面我们需要解决的需求之一, 三种BuildTypes运行时,生成的APP会被替换掉,最后运行三种BuildTypes在手机中只生成一个APP。如何让开发,测试,生产环境的APP存在于同一个手机上。为了解决这个问题,我们先来看看如何为不同的环境指定不同的应用名称及图标,用以安装后展示效果

为三个环境指定不同的应用名称,应用图标

按照开发-测试-生产的顺序准备三张应用图标

905242b567e0

ic_launcher_dev.png

905242b567e0

ic_launcher_test.png

905242b567e0

ic_launcher_release.png

strings.xml

test

DEV

TEST

RELEASE

android {

...

buildTypes {

debug{

minifyEnabled false

proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/debug\""

manifestPlaceholders = [

app_icon :"@mipmap/ic_launcher",

app_label : "@string/app_name"

]

}

release{

buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/release\""

signingConfig signingConfigs.release

manifestPlaceholders = [

app_icon :"@mipmap/ic_launcher",

app_label : "@string/app_name"

]

}

appDev{

buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/appDev\""

signingConfig signingConfigs.release

manifestPlaceholders = [

app_icon :"@mipmap/ic_launcher_dev",

app_label : "@string/app_name_dev"

]

}

appTest{

buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/appTest\""

signingConfig signingConfigs.release

manifestPlaceholders = [

app_icon :"@mipmap/ic_launcher_test",

app_label : "@string/app_name_test"

]

}

appRelease {

buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/appRelease\""

signingConfig signingConfigs.release

manifestPlaceholders = [

app_icon :"@mipmap/ic_launcher_release",

app_label : "@string/app_name_release"

]

}

}

}

package="com.minicup.test">

android:allowBackup="true"

android:icon="${app_icon}"

android:label="${app_label}"

android:supportsRtl="true"

android:theme="@style/AppTheme">

通过设置不同的BuildVariants获得的结果:

905242b567e0

BuildType.appDev

905242b567e0

BuildType.appTest

905242b567e0

BuildType.appRelease

以上结果针对BuildType的应用名称,应用图标,及打开APP中的BASE_URL都一一对应。接下来让三种BuildType运行在一台机器上。

三种不同的BuildType,安装在同一设备上。

android {

...

buildTypes {

...

appDev{

buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/appDev\""

signingConfig signingConfigs.release

manifestPlaceholders = [

app_icon :"@mipmap/ic_launcher_dev",

app_label : "@string/app_name_dev"

]

applicationIdSuffix = ".dev"

}

appTest{

buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/appTest\""

signingConfig signingConfigs.release

manifestPlaceholders = [

app_icon :"@mipmap/ic_launcher_test",

app_label : "@string/app_name_test"

]

applicationIdSuffix = ".test"

}

appRelease {

buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/appRelease\""

signingConfig signingConfigs.release

manifestPlaceholders = [

app_icon :"@mipmap/ic_launcher_release",

app_label : "@string/app_name_release"

]

applicationIdSuffix = ".release"

}

}

}

切换三种BuildType,安装APP到设备中:

905242b567e0

image.png

实现一套代码维护两个应用,每个应用都有dev,test,release三个构建类型,两个应用的图标,名称,包名不同

app build.gradle 指定不同productFlavor下的包名,及不同buildType下的图标,名称及包名后缀

apply plugin: 'com.android.application'

android {

signingConfigs {

release {

storeFile file('appDev.jks')

storePassword '123456'

keyAlias = 'appDev'

keyPassword '123456'

}

}

compileSdkVersion 28

defaultConfig {

minSdkVersion 19

targetSdkVersion 28

versionCode 1

versionName "1.0"

testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

flavorDimensions "default"

}

buildTypes {

appDev{

buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/appDev\""

signingConfig signingConfigs.release

manifestPlaceholders = [

app_icon :"@drawable/ic_launcher_dev",

app_label : "@string/app_name_dev"

]

applicationIdSuffix = ".dev"

}

appTest{

buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/appTest\""

signingConfig signingConfigs.release

manifestPlaceholders = [

app_icon :"@drawable/ic_launcher_test",

app_label : "@string/app_name_test"

]

applicationIdSuffix = ".test"

}

appRelease {

buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/appRelease\""

signingConfig signingConfigs.release

manifestPlaceholders = [

app_icon :"@drawable/ic_launcher_release",

app_label : "@string/app_name_release"

]

applicationIdSuffix = ".release"

}

}

productFlavors {

orange {

applicationId "com.minicup.orange"

}

green {

applicationId "com.minicup.green"

}

}

//去掉默认的debug及release两个buildType

variantFilter { variant ->

if(variant.buildType.name.equals('release') || variant.buildType.name.equals('debug')) {

variant.setIgnore(true)

}

}

}

...

*创建以下的目录结构,不同productFlavor对应相应的图标,名称

905242b567e0

image.png

green目录下的图标及名称:

905242b567e0

ic_launcher_dev.xml

905242b567e0

ic_launcher_test.xml

905242b567e0

ic_launcher_release.xml

DEV_G

TEST_G

RELEASE_G

orange目录下的图标及名称:

905242b567e0

ic_launcher_dev.xml

905242b567e0

ic_launcher_test.xml

905242b567e0

ic_launcher_release.xml

DEV_O

TEST_O

RELEASE_O

MainActivity

public class MainActivity extends AppCompatActivity {

private TextView mTextView;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mTextView = (TextView) findViewById(R.id.textView);

mTextView.setText(BuildConfig.FLAVOR + " "+ BuildConfig.BUILD_TYPE);

}

}

同步项目,查看BuildVariant, 生成了两个应用对应的构建类型 2(productFlavor)*3(buildType)=6(buildVariant)

905242b567e0

image.png

执行assemble任务:

905242b567e0

image.png

验证APP,将生成的6个APP安装到设备中

905242b567e0

image.png

不同的productFlavor,不同的buildType生成的应用可安装到同一个设备

同一个productFlavor的不同buildType,根据之前配置生成不同名称,不同图标,不同包名的app

905242b567e0

image.png

905242b567e0

image.png

905242b567e0

image.png

905242b567e0

image.png

905242b567e0

image.png

905242b567e0

image.png

设置生成APP的文件名称

productFlavors {

orange {

applicationId "com.minicup.orange"

versionCode 2

versionName "2.2"

}

green {

applicationId "com.minicup.green"

versionCode 3

versionName "3.3"

}

}

applicationVariants.all { variant ->

variant.outputs.all { output ->

//产品名称_产品版本号_日期_软件环境

outputFileName = "${variant.productFlavors[0].name}_" +

"v${variant.versionName}_" +

"${releaseTime()}_" +

"${variant.buildType.name}" +

".apk"

}

}

def releaseTime(){

return new Date().format("yyyy-MM-dd")

}

执行assemble任务:

905242b567e0

image.png

集成JPush时,遇到的问题

按照以上方法配置JPush时,打好的包,不能同时安装在同一个设备中

905242b567e0

image.png

目前只能准备两台设备,同一设备只能安装同一buildtype的应用

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

android build type,Android应用构建-BuildType ProductFlavor 的相关文章

随机推荐