• Gradle for Android ( 构建变体 )


    链接:

    http://77blogs.com/?p=38

    https://www.cnblogs.com/tangZH/p/10999060.html

    有时候我们一个app需要有不同的版本,不同的版本又会使用不同的配置,我们可以使用gradle进行管理。


    • Build types
    • Product flavors
    • Build variants
    • Signing configurations

    一、构建版本Build types:

    常见的构建版本有debug与release。

    buildTypes {
     release {
       minifyEnabled false
       proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
     }
    }

    自定义构建版本:

    custom {
        applicationIdSuffix ".custom"
        versionNameSuffix ".custom"
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        signingConfig signingConfigs.readerDaquanConfig
    }

    除了debug构建版本不需要签名外,其它的都是需要配置签名的,不然无法运行在手机上,该版本定义了新的applicationId与版本号。不同构建版本的applicationId如下:

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

    也可以采用继承的方式:

    custom.initWith(buildTypes.debug)
    custom {
       applicationIdSuffix ".custom"
       versionNameSuffix ".custom"
       minifyEnabled false
       proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
       signingConfig signingConfigs.readerDaquanConfig
    }

    custom继承debug构建版本的配置,custom中的配置会覆盖debug的配置。

     

    在BuildConfig中添加变量

    custom {
    applicationIdSuffix ".custom"
    versionNameSuffix ".custom"
    buildConfigField("String", "name",""custom app"")
    buildConfigField("int", "id", "0")
    minifyEnabled false
    proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    signingConfig signingConfigs.readerDaquanConfig
    }

    之后我们可以看到:

    注意如果要添加的是String,那么双一号里面需要再一个双引号标识字符串""custom app"",斜杆是对里面双引号进行转义。

    Source sets

    当创建了一个新的build type之后,Gradle也会创建一个新的source set。默认的source set目录会放在相同的Build Type的目录下。当你创建一个新的build type时,该目录不会自动创建,你必须在你使用代码与资源前自己为每一个build type创建source set目录。
    三种buildType的目录结构如下:
    app
    └── src
    ├── debug
    │ ├── java
    │ │   └── com.package
    │ ├── res
    │ │ └── layout
    │ │       └── activity_main.xml
    │ └── AndroidManifest.xml
    ├── main
    │ ├── java
    │ │   └── com.package
    │ ├── res
    └── MainActivity.java
    └── Constants.java
    │ └── AndroidManifest.xml
    ├── custom
    │ ├── java
    │ │   └── com.package
    ├── drawable
    └── layout
    └── activity_main.xml
    │ ├── res
    │ │ └── layout
    │ │       └── activity_main.xml
    │ └── AndroidManifest.xml
    └── release
        ├── java
        │   └── com.package
        │       └── Constants.java
        └── AndroidManifest.xml

    假如我们自己建立custom的source set 

    我们使用不同的构建版本便会使用不同的source set。当使用不同的source sets的时候,资源文件的处理需要特殊的方式。Drawables和layout文件将会复写在main中的重名文件,但是values文件下的资源不会。gradle将会把这些资源连同main里面的资源一起合并。(如果出现资源重复异常,请clean一下工程)

    例如,在main中的string.xml为:

    <resources>
        <string name="app_name">BuildTypeProject</string>
        <string name="hello_name">BuildTypeHello</string>
    </resources>

    在custom版本中为:

    <resources>
        <string name="app_name">BuildTypeCustomProject</string>
    </resources>

    当我们构建custom版本的时会合并为:

    <resources>
        <string name="app_name">BuildTypeCustomProject</string>
        <string name="hello_name">BuildTypeHello</string>
    </resources>

    当你创建一个新的构建版本而不是custom,最终的strings.xml将会是main目录下的strings.xml。

    manifest也和value文件下的文件一样。如果你为你的构建版本创建了一个manifest文件,那么你不必要去拷贝在main文件下的manifest文件,你需要做的是添加标签。Android插件将会为你合并它们。

     

    但是需要注意,当我们添加.java文件到custom版本中,你可以添加相同的类到debug和release版本,但是不能添加到main版本。如果你添加了,会抛出异常。这时候我们如果构建custom版本,那么便会使用custom对应source set中的.java文件。

     


    依赖包

    每一个构建版本都有自己的依赖包,gradle自动为每一个构建的版本创建不同的依赖配置。如果你想为debug版本添加一个logging框架,你可以这么做:

    dependencies {
       compile fileTree(dir: 'libs', include: ['*.jar'])
       compile 'com.android.support:appcompat-v7:22.2.0'
       debugCompile 'de.mindpipe.android:android-logging-log4j:1.0.3'
    }

    product flavors

    不同的生产版本。

    product flavors极大简化了基于相同的代码构建不同版本的app。

    创建product flavors

    android {
        productFlavors {
           vivo {
                applicationId "vivo"
                versionCode 1
                minSdkVersion 15
            }
            oppo {
                applicationId "oppo"
                versionCode 2
                minSdkVersion 15
            }
        }
    }

    这时候AS 3.0以上会报错ERROR: All flavors must now belong to a named flavor dimension

    没有给它们设置一个风味维度,我们可以加上

    flavorDimensions "default"

    flavorDimensions "default"
    android {
        productFlavors {
           vivo {
                applicationId "vivo"
                versionCode 1
                minSdkVersion 15
            }
            oppo {
                applicationId "oppo"
                versionCode 2
                minSdkVersion 15
            }
        }
    }

    给这些产品版本默认一个风味维度,具体有何作用,等会会讲。

     

    这时候我们会在左下角的窗口看到这么多个变体:

    如果找不到该窗口,可以在这里打开:

     由于我们之前在custom构建版本上设置了applicationIdSuffix ".custom",所以,当我们运行oppoCustom版本的时候,applicationId为oppo.custom

    Source Set

    product Flavors也有自己的代码文件夹。创建一个特殊的版本就像创建一个文件夹那么简单。如下图所示:

    但是值得注意的是,我们无法再vivo文件夹里相同的包中添加构建版本已经有的.java文件,添加了会报异常。而对于资源文件,我们可以添加构建版本里面有的文件,但是这个产品版本所对应的目录的优先级低于Build type,也就是说,当Custom目录有一张图片,vivo目录也有一张图片,那么当我们运行打包vivoCustom版本的时候,使用的是custom里面的图片。除非我们建立的文件夹是vivoCustom,那么它的优先级便会是最高的。

     

    Multiflavor variants

    在某些情况下,你可能希望创建一些联合的Product Flavors,这个时候便要使用到我们刚刚所说的flavorDimensions 了。

    设想一下,假如我们需要打包两个渠道的app:vivo和oppo,而这两个渠道的app各自有付费版与免费版,那么我们就需要用到多维度了。

    首先定义两个维度:渠道channel,付费与免费:money

    flavorDimensions "channel","money"

    flavorDimensions "channel","money"
    android {
        productFlavors {
           vivo {
                dimension "channel"
                applicationId "vivo"
                versionCode 1
                minSdkVersion 15
            }
            oppo {
                dimension "channel"
                applicationId "oppo"
                versionCode 2
                minSdkVersion 15
            }
            free {
                dimension "money"
            }
            vip {
                dimension "money"
            }
        }
    }

    当你添加了flavor dimensions,你就需要为每个flavor添加dimension,否则会提示错误。

    之后我们可以看到这么多个变体:

     而我们定义多个维度的顺序是很重要的,因为当你在各个维度各自定义了同一个常量的值,比如:buildConfigField("String", "name",""custom app""),总是以第一维度的为准。


    Build variants

    构建变体

    构建变体是构建版本和生产版本的结合体。当你创建了一个构建版本或者生产版本,同样的,新的变体也会被创建。

    像我们上图便有这么多的变体:

    我们可以在这个窗口进行切换,然后运行不同的变体。

    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联合。
     

    Source sets

    构建变体也可以有自己的资源文件夹,举个例子,你可以有src/vivoVipCustom/java/。原理与上面的类似


    Resource and mainfest merging

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

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

    如果一个资源在main中和在flavor中定义了,那么那个在flavor中的资源有更高的优先级。这样那个在flavor文件夹中的资源将会被打包到apk。而在依赖项目申明的资源总是拥有最低优先级。

    当然,如果你建立的目录是变体的目录入:vivoVipCustom,那么它的优先级自然是高于Build type


    创建构建变体

    关于如何构建变量,上面已经说了,不再重复。

    flavorDimensions "channel","money"
    android {
        productFlavors {
           vivo {
                dimension "channel"
                applicationId "vivo"
                versionCode 1
                minSdkVersion 15
            }
            oppo {
                dimension "channel"
                applicationId "oppo"
                versionCode 2
                minSdkVersion 15
            }
            free {
                dimension "money"
                resValue "color", "colorfree", "#ff8888"
            }
            vip {
                dimension "money"
                resValue "color", "colorfree", "#ff0000"
            }
        }
    }

    resValue "color", "colorfree", "#ff8888"表示添加颜色名为colorfree的颜色


    变体过滤器

    忽略某个变体也是可行的。这样你可以加速你的构建当使用assemble的时候,这样你列出的tasks将不会执行那么你不需要的变体。你可以使用过滤器,在build.gradle中添加代码如下所示:

    android.variantFilter { variant ->
        if(variant.buildType.name.equals('release')) {
            variant.getFlavors().each() { flavor ->
                if (flavor.name.equals('vivo')) { variant.setIgnore(true);
                }
            }
        }
    }

    发现相关的变体不见了:


    Signing Configurations


    在你发布你的应用之前,你需要为你的app私钥签名。如果你有付费版和免费版,你需要有不同的key去签名不同的变体。这就是配置签名的好处。配置签名可以这样定义:

    android {
           signingConfigs {
               custom.initWith(signingConfigs.debug)
               release {
                   storeFile file("release.keystore")
                   storePassword"secretpassword"
                   keyAlias "gradleforandroid"
                   keyPassword "secretpassword"
               }
          }
    }

    在这个例子中,我们创建了2个不同的签名配置。debug配置是as默认的,其使用了公共的keystore和password,所以没有必要为debug版本创建签名配置了。custom配置使用了initWith()方法,其会复制其他的签名配置。这意味着custom和debug的key是一样的。

    release配置使用了storeFile,定义了key alias和密码。当然这不是一个好的选择,你需要在 Gradle properties文件中配置。

    当你定义了签名配置后,你需要应用它们。构建版本都有一个属性叫做signingConfig,你可以这么干:

    android {
           buildTypes {
               release {
                   signingConfig signingConfigs.release
               } 
           }
    }

    上例使用了buildTypes,但是你可能需要对每个版本生成不同的验证,你可以这么定义:

    android {
           productFlavors {
               vivo{
                   signingConfig signingConfigs.release
               }
           }
    }

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

    android {
           buildTypes {
               release {
                   productFlavors.vivo.signingConfig signingConfigs.vivo
                   productFlavors.oppo.signingConfig signingConfigs.oppo
               } 
           }
    }

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

  • 相关阅读:
    纯css3实现旋转的太极图
    webstorm9.3 安装less 编译css教程
    javascript之查找数组中最小/最大的数
    javascript基础之打印乘法表
    javascript之查找数组元素
    jvascript 顺序查找和二分查找法
    Vue基础知识之常用属性和事件修饰符(二)
    Vue源码(一)
    BFC以及margin的深入探究
    jQuery中Ajax参数详细介绍
  • 原文地址:https://www.cnblogs.com/tangZH/p/10999060.html
Copyright © 2020-2023  润新知