Android 进阶——Android Studio 项目结构详细述及Gradle脚本语法android子节点buildTypes、productFlavors、variantFilt完全解析(二)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/CrazyMo_/article/details/86703681

引言

前面一篇文章Android 进阶——Android Studio 项目结构详细述及Gradle脚本语法完全解析(一)总结了下Android Studio中组织Android项目结构的形式,详细介绍了Project下几乎所有重要文件及目录的重要作用,而对于我们Android开发来说比较重要的是编译脚本的gradle.build文件,接下来系列文章就好好总结下关于如何解读、配置和编写正确的gradle.build文件,这篇首先总结android节点下defaultConfigproductFlavorsvariantFilterbuildTypesexternalNativeBuild的配置。Gradle系列文章链接如下:

一、项目Project根目录下的build.gradle

build.gradle脚本文件可以看成是org.gradle.api.Project的映射,而最外层的节点名称映射到org.gradle.api.Project中对应的方法
项目Project根目录下的build.gradle是用配置所有子Module下的gradle执行的时候所需要的信息。

二、子Module目录下的build.gradle

和Project目录下的build.gradle大同小异,最外层的节点映射到org.gradle.api.Project下对应的方法(android节点除外),虽然没有定义在org.gradle.api.Project里但是可以通过Android插件来支持配置,大体上可以把结构划分为:引入android插件、配置android插件、配置编译环境。
在这里插入图片描述
app和lib Module类型中android节点所支持的属性可查阅Android Plugin DSL Reference中的Extension types部分,而且Gradle的配置非常灵活同样的配置可以在不同的节点进行配置来实现统一效果。

三、android节点

android节点内部所支持的配置子节点,根据引入不同类型的插件的来自不同的类,本质上他们都是来自于BaseExtension及其子类。

插件类型 说明
AppExtension 当使用apply plugin: 'com.android.application’引入appplication类型插件时,android节点内可配置的子节点来源AppExtension
LibraryExtension 当用 com.android.library 引入库插件时来源LibraryExtension
TestExtension 当用com.android.test 引入测试插件时来源TestExtension
FeatureExtension 当用 com.android.feature 时来源FeatureExtension

AppExtension中有个applicationVariants属性可以在代码中获取我们配置的所有内容,同样地LibraryExtension中也有个类似的libraryVariants

在这里插入图片描述
android节点是用于配置android 插件本身的,另外想要查看各子节点下还可以配置哪些属性,可以在Android Studio 鼠标点击对应的节点即可看到,其实每一个节点可以映射成一个JavaBean ,自然那些属性也会被映射成对应的成员变量。
在这里插入图片描述

1、defaultConfig节点

defaultConfig节点是在android节点内用于配置编译环境,深追进去发现其实它所有支持的配置的子节点来自于ProductFlavor子节点的话就是通过闭包委托形式配置属性的话就是直接配置

子节点或属性名称 说明
applicationId 应用的唯一ID,参见1.1
consumerProguardFiles 打包库Module发布AAR时配置的混淆文件,参见1.2
proguardFiles 当前Module使用的混淆文件
signingConfig 当前Module打包签名的配置
versionCode apk的版本号,整数
versionName apk的版本名称,与版本号一样编译后对应的清单文件中
externalNativeBuild 构建NDK的配置
ndk 来自于com.android.build.gradle.internal.dsl.NdkOptions的映射,配置打包apk时如何处理相应的jni文件,比如说在源文件下有多个CPU架构的so,默认下打包之后的apk每个架构的都会包含进去,如果此时在ndk下配置了abiFilters ‘armeabi-v7a’ 则apk里只会存在armeabi-v7a下的so
multiDexEnabled 传递一个布尔值设置是否允许支持分包,典型的是处理app中方法数超过65k时需要开启分包,因为方法的索引是以short类型(2个字节)存储的,而short最大是0xffff
multiDexKeepFile 配置分包原则,配置需要保存到主dex的类的文件(不支持ProGuard语法),每一行表示要分到主dex的一个类,有多少行表示多少个类需要分配到主Dex,比如说com/cmo/x/xx.class
multiDexKeepProguard 也是配置需要保存到主dex的类,使用的是Proguard的写法,比如说–keep com.cmo.x.xx.**{*;}
applicationIdSuffix 应用ID的后缀,效果就是配置了这个只会自动拼接到applicationId的值上作为最终的应用ID,不能使用关键字
versionNameSuffix 版本名称后缀,效果与应用后缀相似,不能使用关键字
manifestPlaceholders 清单文件的常量占位符相当于给清单文件传递参数,参见1.4
vectorDrawables 配置svg的相关信息,在某些版本系统会自动把svg生成相应的png资源,可以配置开启支持和自动生成对应的png在哪个屏幕密度下等。
dimension 在默认的productFlavor——defaultConfig下无任何用处,但作用在自已定义的productFlavor,具体参见2
matchingFallbacks Specifies a sorted list of product flavors that the plugin should try to use when a direct variant match with a local module dependency is not possible.
testApplicationId Test application ID,test开头都是与测试相关的配置
testFunctionalTest See instrumentation.
testHandleProfiling See instrumentation.
testInstrumentationRunner Test instrumentation runner class name.
testInstrumentationRunnerArguments Test instrumentation runner custom arguments.
wearAppUnbundled Returns whether to enable unbundling mode for embedded wear app. If true, this enables the app to transition from an embedded wear app to one distributed by the play store directly.
javaCompileOptions Options for configuration Java compilation,用于配置注释处理器的选项(用的不多)

在这里插入图片描述

1.1、applicationId

应用的唯一ID(默认就是你的包名),虽然编译后与清单文件中package的值相同,但是作用是完全不同的,清单文件中的包名作用只是告诉编译器配置的组件属于哪个包(编译时会把 . 替换成package的值),而applicationId则是Android系统进行签名验证等一系列安全管理的依据,只要你applicationId相同就会被认为是同一个应用,无论你源码是否一致。但是如果在buid.gradle文件中配置了新的applicationId之后,那么编译后的清单文件有所改变,如下所示
在这里插入图片描述

扫描二维码关注公众号,回复: 7564183 查看本文章

1.2、consumerProguardFiles

打包库Module发布AAR时配置的混淆文件,如果没有配置这个属性,在其他项目引用AndroidLib 项目且开启minifyEnabled时或许会报错,因为主项目不会自主引入依赖库的ProguardFile文件,必须在主项目中配置consumerProguardFiles节点,这样主项目就会引入依赖库的gradle文件中的(默认为release变体)下ProguardFile

1.2.1、app 引入默认的library 的defaultPublishConfig 指向的变体配置

如果不指定defaultPublishConfig 默认是指向release 变体的配置。
在这里插入图片描述

1.2.2、app 引入自己指定的library 的的变体配置

通过compile project(path:’:library’,configuration:‘release’) 在app 引入的时候指定对应的变体。默认情况下在library的build.gradle文件中既不配置defaultPublishConfig 也不配置publishNonDefault时,插件只会生成defaultPublishConfig 对应的变体的配置(即只生成release的配置),所以我们想要引入非默认变体的配置时除了在引入依赖的时候指定,还需要在library配置,主要有两种形式(任选一种):

  • publishNonDefault配置为true,则会生成所有变体对应的配置并对外发布出来。
  • defaultPublishConfig 设置发布指定的变体对应的配置信息,然后再引入依赖时传递过来。

在这里插入图片描述

1.3、defaultConfig下的externalNativeBuild

在defaultConfig节点内的externalNativeBuild子节点映射自com.android.build.gradle.internal.dsl.ExternalNativeBuild,Native编译环境的配置(来自于CoreExternalNativeCmakeOptions),比如说选择哪种方式映射:CmakeOptions的cmake还是NdkBuildOptions的ndk等。

package com.android.build.gradle.internal.dsl;
public class ExternalNativeBuild implements CoreExternalNativeBuild {
    private NdkBuildOptions ndkBuild;
    private CmakeOptions cmake;
    ....
    

1.4、manifestPlaceholders

清单文件的常量占位符相当于给清单文件传递参数,在build.gradle文件里通过配置一个键值对[键,值]的形式

//auther为键,可以是任意值,后面为对应的值
manifestPlaceholders=[auther:'666']

则可以在清单文件中通过 ${键} 引用

//编译合并之后value值则变为666
<meta-data  android:name="cmo"  android:value="${auther}"  / >

1.5、defaultConfig节点重要的方法

通常有对应的属性,也会有对应的方法,所以在defaultConfig节点下除了配置属性节点也可以直接调用对应的方法

  • void buildConfigField(String type, String name, String value)

一般当我们执行Gradle下Tasks>other节点下>generateDebugBuidConfig,就会在对应模块下的build目录下的source/buildConfig/debug/包名/BuildConfig.java生成对应信息,,而通过这个方法就是手动创建一个自定义的buildConfigField

defaultConfig {
//1.在defaultConfig下配置了一个String类型的常量名称为Name,值为CrazyMo,编译之后则自动插入到BuildConfig.java中
        buildConfigField('String','Name','"CrazyMo"')
        //<=>也是在defaultConfig下配置了一个String类型的常量名称为Name,值为CrazyMo
        //buildConfigField 'String','Name','"CrazyMo"'
        ...
        }

编译之后(也可以部分编译——运行generateDebugBuidConfig task)就会在BuildConfig.java保存了新的成员属性,就可以在代码中通过BuildConfig去使用BuildConfig里的属性。
在这里插入图片描述

  • void resValue(String type, String name, String value)

buildConfigField方法类似,只不过resValue添加的是资源,是在编译过程中给res文件夹对应类型的资源添加新值,会在**\build\generated\source\r\debug\com\crazymo\productflavor\R.java**中看到(不同版本的Android Studio 可能路径有所不同,本文及其他相同系列文章是基于AS3.0.1)

    defaultConfig {
    //编译之后则可以在代码中通过R.string.blog来使用
        resValue('string','blog','"csdn"')
        //resValue 'string', 'blog', 'csdn'

在这里插入图片描述

2、productFlavors节点

前面也讲过defaultConfig其实就是Android插件给我们生成的一个默认productFlavors节点,所以两者可以配置的节点名称和功能大同小异,自然两者之间也是同级的,尤其是在多渠道打包的时候极为重要。

2.1、productFlavors节点下配置的大部分属性会覆盖defaultConfig里相同属性,但是有些会附加到defaultConfig中配置的值后面,比如说前缀和后缀属性。

2.2、配置自定义productFlavors

  • 要配置自定义productFlavors,首先需要使用通过AppExtentison下的flavorDimensions(String… dimensions)方法创建来指定该项目的产品维度的名称

  • 在productFlavors节点内创建自己productFlavors名称并给其对应的dimension节点配上创建的维度

  • 配置各自维度中的其他属性

2.3、Build Variant及productFlavors 与代码源集

默认情况下一个项目只有一个主源集(mian source set),但是其实我们还可以给不同的Build Variant和productFlavors 分别配置各自的源集,配置了productFlavors 就可以配置不同的productFlavors对应自己独立的子源集,不同的productFlavors和不同的Build Variant都可以配置各自独立的源集,如下图:
在这里插入图片描述
比如说当我们通过Project模式下的src目录->右键new->Folder创建了一个free的源集时候,当我们在编译的时候选择的Build Variant是含有free时,这个free源集(包含代码、资源、清单、文件等所有东西)会被自动合并到主源集中,所以我们可以在主源集里调用到free 源集中的公共资源,而如果此时选择的Build Variant不含有free 则在主源集中无妨访问,但同样的两个都含有free的源集中类名和资源等都不能重复,因为他们都会在对应的情况下被合并到主源集
在这里插入图片描述

2.4、productFlavors 与依赖分组

productFlavors除了可以影响项目的源集,还可以影响到dependencies节点中的依赖分组,默认情况下系统只提供了几个依赖分组如implementation、api等,但是我们配置了productFlavors 之后,就会自动生成对应productFlavors 的依赖分组(格式形如:productFlavors+系统依赖分组 或者 buildType + 系统依赖分组 ,不存在组合型的:productFlavors+ buildType + 系统依赖分组),作用和机制和源集大同小异。但如果需要创建组合型的依赖分组,则可能需要自己去实现逻辑,本质上就需要去操作class字节码了,productFlavors 与依赖分组有三种类型:

  • 无需任何声明或实现直接就可以在dependencies中使用的格式形如:productFlavors+系统依赖分组 或者 buildType + 系统依赖分组

在这里插入图片描述

  • 只需要在与android 节点同级的 configurations中声明就可使用
    创建 freeArmeabiV7aDebugCompile恰好是完整的Build Variant取值,无需实现具体逻辑,就可以在dependencies中使用
//与android 节点同级
configurations{
	freeArmeabiV7aDebugCompile{
	}
}
  • 需要在与android 节点同级的 configurations中声明且自己实现具体逻辑之后才能使用的
//与android 节点同级
configurations{
	//创建 freeDebugCompile不是完整的Build Variant取值,若不实现具体逻辑在dependencies中使用也没有依赖效果
	freeDebugCompile{
		//todo 实现具体逻辑
	}
}

2.5、productFlavors和dimension最终是要组合成为不同版本的Build Variant

简单来说productFlavors是用于配置自定义的Build Variant,通过Build Variant就可以编译不同的版本的apk。首先是未配置productFlavors采用默认的defaultConfig进行编译时的结果
在这里插入图片描述
使用productFlavors进行了配置,从产品架构和商业版本定义了两个维度,再结合两个维度定义了四种风味:
在这里插入图片描述

3、variantFilter节点

如其字面意思一样过滤变体的作用,一般来说如果配置了不同的Flavors节点就会自动生成相应的Build Variant,但是如果需要把一些变体筛选,比如下面这样在Build Variant列表中自动过滤掉符合条件的Build Variant

在这里插入图片描述

4、externalNativeBuild

defaultConfig 同级的externalNativeBuild节点用于配置NDK的构建文件,而内部的externalNativeBuild则用于指导NDK构建

//引入插件
apply plugin: 'com.android.application'
//配置android插件
android {
	...
    //默认 产品风味
    defaultConfig {     
        //构建ndk的编译配置,使用什么样的方式进行编译那些内容。
        externalNativeBuild {
            //android.mk
            ndkBuild {
            }
          //cmake
            cmake{
            }
        }
        //定义打包的cpu架构支持,默认全架构的
        ndk{
            abiFilters 'armeabi-v7a'
        }
    }
    //指定ndk的构建文件,要编译的内容写在构建文件中
    externalNativeBuild{
        ndkBuild {
            path 'Android.mk'
        }
        cmake{
            path 'CMakeLists.txt'
        }
    }
	...
}


未完待续…

猜你喜欢

转载自blog.csdn.net/CrazyMo_/article/details/86703681