前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Gradle For Android(4)--构建不同的版本

Gradle For Android(4)--构建不同的版本

作者头像
None_Ling
发布2018-10-24 14:36:59
1.8K0
发布2018-10-24 14:36:59
举报
文章被收录于专栏:Android相关Android相关

介绍

当构建App的时候,通常都会有不同的版本。比如说测试版本,正式版本,Debug版本等等。而这些版本通常有不同的配置,比如说服务器的域名,Log开关,付费开关等等特性。

之前我们看到了Release以及Debug版本的概念,而接下来会介绍product flavors的概念。而这也可以帮助我们管理不同的版本。Build TypeProduct Flavors总是联合在一起的,它两结合的结果就称之为Build Variant

Build Types

在Gradle的Android Plugin中,Build Type用于定义App以及Library如何构建。每一个Build Type都会指明是否为Debug,Application Id,是否无用的资源应该被删除掉等等。你也可以在buildTypes的代码块中定义多种Build Types。Android Studio默认生成的标准的build Types代码块如下:

代码语言:javascript
复制
android {
       buildTypes {
           release {
               minifyEnabled false
               proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
           }
} }

一个新的Module默认的build.gradle文件中会配置一个release的Build Type。这个build type通过设置minifyEnabled为false禁用删除无用的Resources,以及定义了默认的ProGuard配置文件。

创建Project的时候不仅仅只有Release的构建类型,默认每个Module都有一个Debug的构建类型。我们可以在里面改改里面的值。

创建Build Type

当默认的配置不满足需求时,我们可以创建我们自定义的Build Type。我们需要做的就是在buildTypes代码块中创建一个新的对象即可,如下所示,创建一个名为staging的Build Type:

代码语言:javascript
复制
android {
    buildTypes {
        staging {
            applicationIdSuffix ".staging"
            versionNameSuffix "-staging"
            buildConfigField "String", "API_URL","\"http://staging.example.com/api\""
        }
    }
}

staging的Build Type定义了一些Application Id的后缀,使得Application的ID与Debug/Release版本不一样。假设你已经有了默认的Build配置,这些版本的ApplicationId会如下:

  • Debug: com.package
  • Release: com.package
  • Staging: com.package.staging

这也就意味着我们能够在同一台设备上安装多个版本的。也可以使用buildConfigField属性定义了不同的URL。

我们也可以通过Copy其他Build Type中的属性,来初始化一个新的BuildType,通过initWith来初始化该BuildType对象。代码如下所示:

代码语言:javascript
复制
android {
       buildTypes {
           staging.initWith(buildTypes.debug)
           staging {
               applicationIdSuffix ".staging"
               versionNameSuffix "-staging"
               debuggable = false
            } 
      }
}

initWith方法创建了一个新的Build Type,并且从一个已经存在的build type中复制这些属性。它也可以重写这些属性,或者定义其他的新的属性。

Source sets

当创建了一个新的build type之后,Gradle也会创建一个新的source set。默认的source set目录会放在相同的Build Type的目录下。当你创建一个新的build type时,该目录不会自动创建,你必须在你使用代码与资源前自己为每一个build type创建source set目录。

这是标准的目录结构,包含了三种Build Type:

代码语言:javascript
复制
app
└── src
├── debug
│ ├── java
│ │   └── com.package
│ ├── res
│ │ └── layout
│ │       └── activity_main.xml
│ └── AndroidManifest.xml
├── main
│ ├── java
│ │   └── com.package
│ ├── res
└── MainActivity.java
└── Constants.java
│ └── AndroidManifest.xml
├── staging
│ ├── java
│ │   └── com.package
├── drawable
└── layout
└── activity_main.xml
│ ├── res
│ │ └── layout
│ │       └── activity_main.xml
│ └── AndroidManifest.xml
└── release
    ├── java
    │   └── com.package
    │       └── Constants.java
    └── AndroidManifest.xml

比如,如果希望在某个build type下替换一些属性,添加一些代码,或者添加一些layouts、strings的话,都是可以做到的。

当使用不同的source sets的时候,Resources会比较特殊。Drawables和layout文件都会被在Main Source Set中的相同名字的资源所重写,但是在values文件夹下面的,如strings、colors、dimens等则不会。Gradle会用main resources来merge各个build type的资源。

例如,如果有一个strings.xml文件在main source set中:

代码语言:javascript
复制
<resources>
       <string name="app_name">TypesAndFlavors</string>
       <string name="hello_world">Hello world!</string>
</resources>

如果在staging的build type中也存在一个strings.xml:

代码语言:javascript
复制
<resources>
       <string name="app_name">TypesAndFlavors STAGING</string>
</resources>

那么最后merge完的strings.xml会如下:

代码语言:javascript
复制
<resources>
       <string name="app_name">TypesAndFlavors STAGING</string>
       <string name="hello_world">Hello world!</string>
</resources>

同样AndroidManifest.xml也是同样的,特定的build type的包会把main source set中的AndroidManifest.xml覆盖。

Product flavors

Build Type可以对于相同的App配置生成不同类型的构建,与Build Type相反,product flavors用来创建相同的App,但是不同的版本。典型的例子就是App有免费和付费版本。另外一个常用就是为只有一个品牌但是有很多客户端,比如说滴滴,外卖,银行等都有司机端和用户端。他们只想修改Logo,Color,Url等等。Product Flavors可以很简单的处理相同的代码生产出不同的版本。

如果你不确定是否需要一个新的build type,或者新的product flavor,那么则需要看一下是否真的需要构建一个新的APP发布到应用市场上。

创建Product Flavors

我们可以通过添加productFlavor代码块来添加一个新的Product Flavor:

代码语言:javascript
复制
android {
       productFlavors {
           red {
               applicationId 'com.gradleforandroid.red'
               versionCode 3
            }
          blue {
            applicationId 'com.gradleforandroid.blue'
            minSdkVersion 14
            versionCode 4
           } 
     }
}

Product Flavors拥有和Build Type不同的属性。因为Product Flavors是一个ProductFlavor类,就像defaultConfig对象一样。这也就意味着,defaultConfig和所有的Product flavors共享相同的Properties。

Source Set

就像Build Types一样,Product Flavors能够拥有他们自己的Source Sets目录。创建一个与Product Flavors名字相同的文件夹。而这个目录的明哲,需要联合它的Build Type以及Flavors,这样用来覆盖那些属性。

比如,你想有一个不同的App Icon在blue flavors中生成一个Release版本的包,那么这个目录应该叫做blueRelease。然后这个组件所关联的目录将会比其他Build Type以及Product Flavors的组件目录优先级会更高。

Multiflavor variants

在某些情况下,你可能希望创建一些联合的Product Flavors。比如说,Client A和Client B都基于相同的代码需要一个免费和付费的版本。创建四个不同的Flavors单独的Settings是不可行的。所以,Combining Flavors可以更高效的使用flavor dimensions

代码语言:javascript
复制
 android {
       flavorDimensions "color", "price"
       productFlavors {
           red {
               flavorDimension "color"
           }
            blue {
               flavorDimension "color"
           }
          free {
               flavorDimension "price"
           }
           paid {
               flavorDimension "price"
          } 
     }
}

当添加了flavor dimensions之后,Gradle希望你为每个Flavor都指定一个flavor dimension。如果你忘记了,则编译时会报错。flavorDimensions数组定义了这些Dimensions,而这些Dimensions的顺序是非常重要的。当需要联合两个Flavors的时候,你可能已经定义了相同的Properties或者Resources。在这种情况下,flavors dimensions数组的顺序决定了哪个flavor配置会覆盖另外的。在之前的例子中,Color Dimension会覆盖Price Dimension 。并且这个顺序,也决定了构建的名字。

假设默认的构建配置有Debug和Release两种Build Type,就像之前的Example中定义的flavors就会生成以下这些版本:

  • blueFreeDebug and blueFreeRelease
  • bluePaidDebug and bluePaidRelease
  • redFreeDebug and redFreeRelease
  • redPaidDebug and redPaidRelease
Build variants

Build Variants仅仅只是Build Types以及Product Flavors的联合。一旦创建了一个新的Build Type或者Product Flavor的话,那么一个新的Variants就会被创建。

例如,如果有一个标准的Debug和Release构建类型,并且你创建了一个Red和Blue的Product Flavor,那么下面的Build Variant就会生成:

Build Variants

这是Android Studio中的一个窗口。可以在tool window的左下角找到它,或者从View->Tool Windows->Build Variants中打开。我们也可以选择其中的Variant来执行任务。如果没有定义任何的Build Types的话,Android Plugin会默认创建一个Debug的Build Type。

Tasks

Android Plugin会为每一个配置的Build Variant创建Tasks。一个新的Android App拥有Debug和Release两种Build Types,所以默认的就会有两个Task,一个是assembleDebug一个是assembleRelease来构建不同的APK。当添加一个新的Build Type的时候,一个新的Task也就会被创建,一旦你开始添加Flavors,一整套Tasks就会被创建,因为每一个BuildType的Tasks都会为每个Product Flavor联合。也就是,一个简单的Build Type和Flavor设置后,就会有三个任务去构建所有的Variants。

  • assembleBlue:使用blue flavor配置并且assemble BlueRelease和BlueDebug
  • assembleDebug:使用Debug Build Type的配置,并且为每一个Product Flavor assemble一个Debug的版本
  • assembleBlueDebug:combines特定的Flavor以及BuildType配置,并且Flavor的设置会覆盖BuildType的设置

每一个BuildType和Product Flavor都会创建新的Tasks。

Source Set

Build Variants是一个联合了BuildType和ProductFlavors并且使用它们自己SourceSet目录的版本。

例如:Variant创建从Debug Build Type以及Blue、Free Flavor的版本,它可以拥有src/blueFreeDebug/java/的Source Set。我们可以在sourceSets代码块中重写它的location。

Resource and manifest merging

Android Plugin需要在打包前对Main的SourceSet以及BuildType的SourceSet进行一次Merge。而且Library工程也会提供额外的资源,它们也会被Merge,例如Manifest.xml等等。也会在其中声明一些权限等。

Resource和Manifest.xml的优先级顺序如下:

Order.png

如果一个Resource声明在Flavor和Main source set中的话,那么Flavor中的值优先级会更高。在这种情况下,Flavor的SourceSet中的资源会被打包到APK中。而Library工程的资源优先级会是最低的。

Creating build variants

Gradle可以很容易的处理复杂的多种构建。甚至当创建两种BuildType和两种Product Flavors的时候。例如:

代码语言:javascript
复制
android {
       buildTypes {
           debug {
               buildConfigField "String", "API_URL","\"http://test.example.com/api\""
           }
           staging.initWith(android.buildTypes.debug)
           staging {
               buildConfigField "String", "API_URL","\"http://staging.example.com/api\""
               applicationIdSuffix ".staging"
           }
       }
       productFlavors {
           red {
               applicationId "com.gradleforandroid.red"
               resValue "color", "flavor_color", "#ff0000"
           }
           blue {
               applicationId "com.gradleforandroid.blue"
               resValue "color", "flavor_color", "#0000ff"
            } 
      }
}

在这个例子中,我们会创建出来四个不同版本的Variants: blueDebugblueStagingredDebugredStaging 每一个都有API_URL以及flavor_color的属性。

以下为blueDebug的样式:

blueDebug

而以下为redStaging的样式:

redStaging

Variant filters

通过Variant fileters的方式,可以完全忽略某种Variant的构建,从而达到使用assemble命令的时候提升构建的速度。并且不会执行的Task也不会打印的Tasks列表中出现。这样也同样会确保build variant不会在Android Studio中显示。

我们可以通过在App或者Library的Root-Level的build.gradle文件中添加以下代码:

代码语言:javascript
复制
android.variantFilter { variant ->
       if(variant.buildType.name.equals('release')) {
           variant.getFlavors().each() { flavor ->
               if (flavor.name.equals('blue')) {
                  variant.setIgnore(true);
            }
       } 
    }
}

在这个例子中,首先检查BuildType是否为Release,然后检查Flavors的名字,如果flavors为blue则忽略。其中variant.getFlovors会获取到flavor dimensions中所有的flavor。

variant filter

可以看到blueFreeReleasebluePaidRelease已经不在列表中。如果直接执行gradlew tasks的话,就会注意到所有和这个variants相关的tasks都不存在了。

Signing configurations

在发布App到Google Play或者其他的商店的时候,我们需要使用一个Private Key对APK进行签名。如果有一个付费和免费的版本,或者不同的客户端版本时,你需要为不同的Flavor版本APK进行不同的签名。

代码语言:javascript
复制
android {
       signingConfigs {
           staging.initWith(signingConfigs.debug)
           release {
               storeFile file("release.keystore")
               storePassword"secretpassword"
               keyAlias "gradleforandroid"
               keyPassword "secretpassword"
        } 
    }
}

在这个例子中,我们创建了两个不同的签名。 debug配置会被Android Plugin自动设置,并且使用一个已知的Password进行签名,所以不需要为Debug的BuildType创建签名配置。而staging配置使用initWith,它是从另外一个签名配置中Copy的属性。这也就意味着staging的构建会和Debug一样的签名,而没有它自己定义的签名。 而release配置则使用storeFile来指定keystore文件,并且定义了Key的别名以及Password。

当定义完了这个签名的配置后,你需要在BuildType或者Flavors中应用一下。BuildType和Flavors都有一个属性叫做signingConfig,如下所示:

代码语言:javascript
复制
android {
       buildTypes {
           release {
               signingConfig signingConfigs.release
            } 
       }
      productFlavors {
           blue {
               signingConfig signingConfigs.release
          } 
      }
}

通过这种方式会对BuildType以及ProductFlavors应用不同的签名。

当签名一个Flavor版本的时候,你需要重写BuildType中的签名配置W。当需要使用相同的BuildType不同版本的Flavors的签名时,可以通过下述方式:

代码语言:javascript
复制
android {
       buildTypes {
           release {
               productFlavors.red.signingConfig signingConfigs.red
               productFlavors.blue.signingConfig signingConfigs.blue
           } 
       }
}

上面这个例子展示了如何在redblue的Release版本使用不同的签名,但是却不影响Debug和Staging的BuildType。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.10.18 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 介绍
  • Build Types
    • 创建Build Type
    • Source sets
      • Product flavors
        • Source Set
          • Multiflavor variants
            • Build variants
              • Tasks
                • Source Set
                  • Resource and manifest merging
                    • Creating build variants
                      • Variant filters
                        • Signing configurations
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档