美文网首页
Gradle 之创建 Build Variants

Gradle 之创建 Build Variants

作者: 风雪围城 | 来源:发表于2018-01-17 23:46 被阅读0次

    什么是 Gradle

    Gradle 是一个高级构建工具。


    Gradle构建流程

    图片来自于 Gradle 官网,根据官网介绍,上图从左往右,依次体现了:Build Anything >> Automate Everything >> Deliver Faster. 据此,我们可以看到它的主要特点:可以构建的种类多,自动化构建过程,快速交付。
    Android Studio 就是使用了这种工具,来完成 APK 的打包过程。如上面所说,这个过程原本是自动化完成的。自动化的东西都是流水线,我们总会有一些自己的需求,这时,就需要自定义配置这个过程。
    下面,主要讨论下构建变体的使用。

    构建变体的需求

    先来说一下这种需求。
    通常,在开发环境中,我们会使用 debug 版本的应用;在发布是时候使用 release 版本。
    在 debug 版本中个,我们会有显示日志的需求;在 release 版本中是不需要的,日志是为了方便我们调试,而且可能包含一些敏感数据。
    在 release 版本中,通常我们需要进行代码混淆,否则,很容易被别人反编译,就像是一个人没有穿衣服,显然,debug 版本就不需要。
    从应用功能上来讲,同一个 APP 在发布的时候,有时候会根据需要发布不同的版本,比如在不同的应用市场上会有一些定制,即使是在同一个市场上,可能也要提供付费版和免费版等等。

    为了解决上述问题,不管是从构建方式的角度,还是应用功能差异性的角度构建 apk 包,我们都需要对这些版本进行管理。Gradle 就提供了这样一个途径,使得我们可以通过修改 构建配置(文件) 的方式以满足特定版本的需求,然后让 Gradle 根据我们的选择自动构建我们想要的应用。
    当然,处理问题的方式不止一种,我们也会有很多替代方案。但是,明明离终点只差一步,为什么还要翻过一座大山呢?

    什么是构建变体

    谈完需求,下面我们来讲讲什么是构建变体,它是通过 BuildType 和 BuildFlavor 组合实现的。如下所示,共产生 6 个变体。

    构建变体

    所谓 BuildType 和 BuildFlavor,即构建类型和构建特征(或者叫产品风味)。

    BuildType,构建类型,主要针对开发生命周期的不同阶段进行配置。一个模块或者项目,默认有两种类型,release 和 debug。 debug 类型下 debuggable 属性是 true,从而使得我们可以打断点进行调试。debug 类型在打包的时候,会使用默认的自动生成的签名,对于 release 类型来说,发布的时候需要使用我们自己的密钥进行签名。同时,我们还可以在发布的时候,进行代码混淆。

    signingConfigs {
            release {
                storeFile file("xxxx.jks")
                storePassword "xxxx"
                keyAlias "xxxx"
                keyPassword "xxxx"
            }
        }
    buildTypes {
            release {
                signingConfig signingConfigs.release
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
    
            debug {
                applicationIdSuffix ".debug"
            }
            //这是自定义的 buildType,继承自 debug
            /*jnidebug {
                initWith debug
                applicationIdSuffix ".jnidebug"
                jniDebuggable true
            }*/
        }
    

    BuildFlavor,构建特征,主要是用以发布给用户不同的应用版本。需要注意的是,这里的版本并非是版本号,而是功能。比如,我们上说所说的免费版、付费版。

     flavorDimensions "default"
        productFlavors {
            free {
                dimension "default"
                applicationIdSuffix ".free"
                versionNameSuffix "-free"
                buildConfigField "String", "NAME", "\"免费版\""
            }
            paid {
                dimension "default"
                applicationIdSuffix ".paid"
                versionNameSuffix "-paid"
                buildConfigField "String", "NAME", "\"付费版\""
            }
            cmpy {
                dimension "default"
                applicationIdSuffix ".cmpy"
                versionNameSuffix "-cmpy"
                buildConfigField "String", "NAME", "\"内部使用\""
            }
        }
    

    如何使用构建变体

    上一节,说了什么是构建变体,但是,我们该怎么使用以满足我们的需求呢?有两个地方,给我们带来了可能性:BuildConfig 和 SourceSet(源集)。

    BuildConfig

    也许你已经注意到了上面 productFlavor 中的

     buildConfigField "String", "NAME", "\"免费版\""
    

    事实上,对于每一种变体,都会有一个 BuildConfig 与之一一对应。
    我们来看看构建变体 free.debug 的BuildConfig:

    public final class BuildConfig {
      public static final boolean DEBUG = Boolean.parseBoolean("true");
      public static final String APPLICATION_ID = "com.ygs.test.free.debug";
      public static final String BUILD_TYPE = "debug";
      public static final String FLAVOR = "free";
      public static final int VERSION_CODE = 1;
      public static final String VERSION_NAME = "1.0-free";
      // Fields from product flavor: free
      public static final String NAME = "免费版";
    }
    

    这些字段都是静态常量,在项目中,我们都可以通过 BuildConfig 直接访问。比如,你可以通过 BuildConfig.DEBUG 判断当前版本是否是 debug 版本;可以通过 BuildConfig.FLAVOR 判断当前的 productFlavor,已决定是否启用某个功能。当然,我们也可以自定义字段,比如:

     buildConfigField "String", "NAME", "\"免费版\""
    

    上述这些字段,无论是自定义的,还是默认的,都可以成为我们在项目中的判断条件。

    选择相应的构建变体打包
    SourceSet

    所以源集,即代码和资源的分组。这可能有点抽象,举个栗子,src/main 就是一个源集。
    每个 buildType 可以有一个源集,每个 buildFlavor 可以有一个源集,每个 buildVariant 同样可以有一个源集。
    其中,src/main 这个源集是所有源集所共有的,除此之外,源集之间互斥。

    使用源集

    如上图所示,一共有三个源集:freeDebug、freeRelease、main。
    注意,freeDebug、freeRelease 实际上是使用 buildVariant 的构建的源集,需要和构建变体的名字一样(当然可以通过配置修改这种默认行为)。
    这里有几点注意事项:

    • 对于 java 文件来讲,freeDebug 中不能出现和 main 中一样在同一个包下类名相同的 java 文件,因为他们之间是共享关系,相当于将 main 中的所有 java 和 freeDebug 合并在一起。如果出现两个相同名字的 java 文件,会报错。freeDebug 和 freeRelease 不同,它们所有的资源都是互斥的,相互不影响,因为我们在构建的时候,也只能选择其中一种进行构建。假设我们选择了 freeDebug,那么 freeRelease 就会被剔除在外。
    • 对于 res 文件夹下的这些资源文件,freeDebug 和 freeRelease 这些源集之间同样是互斥的,相互没有任何影响。但是对于不同源集和 main之间,却存在着资源合并或替换的情况。
      对于 drawable 及其相关文件夹下的图片而言,freeDebug 中的图片会直接覆盖 main 中的同名图片。对于 layout 文件夹下的布局文件也是这样。
      但是,对于 values 文件夹下的 xml 文件来说,确是文件内容的合并。比如在源集 main 中的 strings.xml 中
    <resources>
    <string name="app_name">App</string>
    <string name="hello_world">Hello world!</string>
    </resources>
    

    在源集 freeDebug 中的 strings.xml 中

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

    它们合并之后就是

    <resources>
    <string name="app_name">FreeDebug</string>
    <string name="hello_world">Hello world!</string>
    </resources>
    

    最后,非常重要的一点,合并或者替换时会遵照优先级:
    buildVariant > buildType > buildFlavor> main > 库依赖项

    总结

    通过 Gradle 创建 构建变体,等于说给了我们告知 Gradle 选择哪些 class 哪些资源编译打包成 apk 的权利,使我们的版本管理更加灵活,方便。

    相关文章

      网友评论

          本文标题:Gradle 之创建 Build Variants

          本文链接:https://www.haomeiwen.com/subject/epzloxtx.html