话题:关于Gradle的知识
1.如何理解Gradle?Gradle在Android的构建过程中有什么作用?
2.实践如下问题:
我们都知道,Android中时常需要发布渠道包,需要将渠道信息附加到apk中,然后在程序启动的时候读取渠道信息。
动态指定一个渠道号(比如1001),那么构建的apk中,请在它的AndroidManifest.xml文件里面的application节点下面添加如下meta-data,请写一段Gradle脚本来自动完成:
<application
android:allowBackup="false"
android:supportsRtl="true">
<meta-data
android:name=“channel"
android:value=“1001" />
</application>
要求:当通过如下命令来构建渠道包的时候,将渠道号自动添加到apk的manifest中。
./gradlew clean assembleRelease -P channel=1001
PS:禁止使用manifestPlaceholders
如何理解Gradle?
Gradle是一个构建工具,它是用来帮助我们构建app的,构建包括编译、打包等过程。我们可以为Gradle指定构建规则,然后它就会根据我们的“命令”自动为我们构建app。
Gradle在Android的构建过程中有什么作用?
Android Studio中默认就使用Gradle来完成应用的构建。实际上,当我们想要更灵活的构建过程时,Gradle就成为了一个编程框架——我们可以通过编程让构建过程按我们的意愿进行。也就是说,当我们把Gradle作为构建工具使用时,我们只需要掌握它的配置脚本的基本写法就OK了;而当我们需要对构建流程进行高度定制时,就务必要掌握Groovy等相关知识了。
assembleRelease过程中调用的Task,如下:
:clean UP-TO-DATE
:app:clean
:app:checkReleaseClasspath 检查环境变量
:app:preBuild UP-TO-DATE
:app:extractProguardFiles 提取proguard文件
:app:preReleaseBuild
:app:compileReleaseAidl NO-SOURCE 编译Aidl文件
:app:compileReleaseRenderscript 编译Renderscript
:app:checkReleaseManifest 检查Manifest
:app:generateReleaseBuildConfig 生成BuildConfig
:app:prepareLintJar 准备Lint
:app:mainApkListPersistenceRelease
:app:generateReleaseResValues 生成values
:app:generateReleaseResources 生成资源文件
:app:mergeReleaseResources merge资源文件
:app:createReleaseCompatibleScreenManifests 创建屏幕兼容清单
:app:processReleaseManifest
:app:splitsDiscoveryTaskRelease
:app:processReleaseResources
:app:generateReleaseSources
:app:dataBindingExportBuildInfoRelease
:app:dataBindingExportFeaturePackageIdsRelease
:app:dataBindingMergeDependencyArtifactsRelease
:app:transformDataBindingBaseClassLogWithDataBindingMergeGenClassesForRelease
:app:dataBindingGenBaseClassesRelease
:app:javaPreCompileRelease
:app:compileReleaseJavaWithJavac
:app:compileReleaseNdk NO-SOURCE
:app:compileReleaseSources
:app:lintVitalRelease
:app:mergeReleaseShaders
:app:compileReleaseShaders
:app:generateReleaseAssets
:app:mergeReleaseAssets
:android-ffmpeg:mergeReleaseConsumerProguardFiles
:app:checkReleaseLibraries
:app:processReleaseJavaRes NO-SOURCE
:app:transformResourcesWithMergeJavaResForRelease
:app:transformClassesAndResourcesWithProguardForRelease
Request to incrementing alive workforce from 0. Current workforce (dead or alive) 0
thread-pool size=4
ProGuard, version 6.0.3
Reading input…
Initializing…
Ignoring unused library classes…
Original number of library classes: 4803
Final number of library classes: 1987
Printing kept classes, fields, and methods…
Inlining subroutines…
Shrinking…
Printing usage to [/home//AndroidStudioProjects/Base/packages/apps//app/build/outputs/mapping//release/usage.txt]…
Removing unused program classes and class elements…
Original number of program classes: 9591
Final number of program classes: 6935
Obfuscating…
Printing mapping to [/home//AndroidStudioProjects/Base/packages/apps//app/build/outputs/mapping//release/mapping.txt]…
Preverifying…
Writing output…
Preparing output jar [/home//AndroidStudioProjects/Base/packages/apps//app/build/intermediates/transforms/proguard//release/0.jar]
:app:transformClassesWithDexBuilderForRelease
:app:transformDexArchiveWithDexMergerForRelease
:app:transformClassesAndDexWithShrinkResForRelease
Removed unused resources: Binary resource data reduced from 2828KB to 2718KB: Removed 3%
:app:mergeReleaseJniLibFolders
:app:transformNativeLibsWithMergeJniLibsForRelease
:app:transformNativeLibsWithStripDebugSymbolForRelease
:app:validateSigningRelease
:app:packageRelease
:app:assembleRelease
实践问题
核心思想:在project afterEvaluate中,找到处理manifest的task,然后在它的doLast后面通过Groovy xml Api直接修改生成的xml文件。
project.afterEvaluate
Gradle提供了对project状态配置监听的接口回调,以方便我们来配置一些Project的配置属性,监听主要分为两大类,一种是通过project(project.beginEvaluate配置前调用,project.afterEvaluate配置后调用)进行 回调,一种是通过gradle(this.gradle.beforeProjectpe配置前调用,this.gradle.afterProject配置后调用)进行回调,作用域也有不同 ,project是只针对当前project实现进行的监听,gradle监听是针对于所有的project而言的。beforeEvaluate方法说的很清楚是配置之前调用,但你要是直接当前build.gradle中使用是肯定不会调用到的,因为Project都没配置好还有他什么事情(也是无奈),afterEvaluates是配置之后调用只要project配置成功均会调用.
Project与Task
在Gradle中,每一个待构建的工程是一个Project,构建一个Project需要执行一系列Task,比如编译、打包这些构建过程的子过程都对应着一个Task。具体来说,一个apk文件的构建包含以下Task:Java源码编译、资源文件编译、Lint检查、打包以生成最终的apk文件等等。
在新建工程的app模块的build.gradle文件的第一行,往往都是如下这句:apply plugin: ‘com.android.application’ . 这句话的意思就是应用“com.android.application“这个插件来构建app模块,app模块就是Gradle中的一个Project。也就是说,这个插件负责定义并执行Java源码编译、资源文件编译、打包等一系列Task。实际上"com.android.application"整个插件中定义了如下4个顶级任务:
assemble: 构建项目的输出(apk)
check: 进行校验工作
build: 执行assemble任务与check任务
clean: 清除项目的输出
当我们执行一个任务时,会自动执行它所依赖的任务。比如,执行assemble任务会执行assembleDebug任务和assembleRelease任务,这是因为一个Android项目至少要有debug和release这两个版本的输出。
import com.android.build.gradle.api.ApplicationVariant
import groovy.xml.XmlUtil
project.afterEvaluate {
android.applicationVariants.each { ApplicationVariant variant ->
String variantName = variant.name.capitalize()
def mergeManifestTask = project.tasks.getByName("process${variantName}Manifest")
mergeManifestTask.doLast { mm ->
//取得manifest路径
String manifestPath = "$manifestOutputDirectory/AndroidManifest.xml"
//取得manifest的文本内容
def manifestContent = file(manifestPath)
if (project.hasProperty("channel")) {
addChannel(manifestContent)
}
}
}
}
def addChannel(File manifest) {
def channelNo = project.property("channel")
def xml = new XmlParser().parse(manifest)
xml.application[0].appendNode("meta-data", ['android:name' : 'channel', 'android:value' : channelNo])
manifest.withPrintWriter("UTF-8") {
XmlUtil.serialize(xml, it)
}
}
结果如下:
参考文献
2.星球作业参考答案-任玉刚