Gradle编译打包Androidapk详细介绍
Gradle编译打包Android apk详细介绍
理解Gradle构建过程,解读Android Gradle插件的配置
阅读本⽂⼀定是要使⽤过Gradle⽣成apk,⽂中不会讲如何安装运⾏Gradle,如有需要可先看⽂末的参考⽂章。
APK包是⼀个ZIP压缩包,从Java源代码、资源⽂件到⽣成这个APK,经过了编译打包⼀系列特定的过程,SDK⽂档
(/docs/tools/building/index.html)中到。⽽这⼀系列特定的过程,重复繁琐,构建⼯具(build tool)就是来流程化这些过程,解放你的双⼿。Ant作为apk早期的构建⼯具,构建过程显得很直观,像配置;Gradle可以⽅便地配置,但更像脚本,可以编程。
理解Gradle构建
1.简单理解构建⼯具
从⼀个程序员的⾓度,你该如何编写代码来⾃动化你的apk⽣成过程呢?⾸先得知道你需要的SDK、NDK在什么位splitter啥意思
置,Android⼯程有⼏个库⼯程,它们的Java源代码、资源⽂件分别有哪些?命令⾏的输⼊参数肯定⽆法满⾜需求,那⾃然⽽然想到配置⽂件。因此你的⾃动化⼯具就是解析这些配置⽂件,按照⽣成apk⽂件要求执⾏的程序。Gradle就是这样的⼯具程序,配置⽂件就是你常见的adle,不过他还提供了更多的功能,如依赖管理,流程控制,还有插件机制来定制你的⽣成过程。
宏晶stc单片机Gradle的编程语⾔是Groovy,其需要的配置⽂件⽀持Groovy。Groovy语⾔像Java⼀样是基于JVM的,⽽且能够很好的⽀持Java,因此可以⽤Java代码编写扩展插件,像普通编程⼀样来写配置⽂件,⽽不⽤像Ant⼀样⽤xml来编写配置逻辑。
2.Groovy
Groovy的语法,把⾃⼰的代码缩略的看上去像脚本,本⼈也只是看了⼀点点⽂档,列出我们常⽤的介绍⼀下:
⾸先Groovy是⾯向对象的动态语⾔
(1)语句的末尾可省略分号
(2)变量定义可以⽤def,也可以直接使⽤
(3)函数定义可以⽤def,也可以不⽤(有返回值声明也可)
函数可省略参数类型
函数调⽤可省略括号
来看个例⼦:
println 'Hello'
int power(int n) { 2**n }
println "2^6==${power(6)}"
第⼀⾏输出字符串Hello,第⼆⾏定义⼀个函数,第三⾏输出函数调⽤值,双引号中间的${}可被解析成表达式运⾏。
(4)List和Map类型
List实现就是Java的java.util.ArrayList,变量由[]包围,⽤逗号分隔,⽐如
def heterogeneous = [1, "a", true] //其元素可以是任何对象
Map的实现是java.util.LinkedHashMap,也是由[]包围,⽤逗号分隔,其中的键值对是key:value形式,如:
def colors = [red: '#FF0000', green: '#00FF00', blue: '#0000FF']
assert colors['red'] == '#FF0000' //取值可以[key]或者.key的形式
== '#00FF00'
(5)闭包(Closures)
闭包我的理解类似C⾥的函数指针,或者说函数对象,可以像函数⼀样调⽤的对象
{ [closureParameters -> ] statements }
例⼦
def testClosure = {int arg1, String arg2 ->//def可省略,参数可省略,默认有it,当只有->表⽰没有参数
苏格兰英格兰威尔士println "arg2:${arg2}" //执⾏的代码,返回值是最后⼀句,也可以⽤return
}
调⽤:
testClosure(1,'2')
testClosure.call(1,'2')
3.Gradle
接着说⾃动化⼯具,编程语⾔有了,那实现⼀系列特定过程⽣成apk,就看如何实现了。Gradle⾥有Project,表⽰⼀个待编译打包处理的⼯程,可以⽣成apk,可以⽣成Jar,Project中可以包含多个Project;每个Project由很多的Task构成,可以理解为不同的过程;每个Task⾥⼜是有不同的Action,和⼀系列要执⾏的操作(或者说你写的要执⾏的语句)。Project中的Task的执⾏顺序,则是由其dependsOn来控制的。
Gradle执⾏时是以task为单位执⾏,在命令⾏中以gradle task来执⾏,这⼀过程的⽣命周期分为三个阶段(官⽅使⽤⼿册中也有详细介绍The Build Lifecycle):
(1)初始化阶段
判断包含哪些⼯程,创建对应的Project实例,可以看到最新执⾏的是在adle中的语句properties是什么文件
(2)配置阶段
创建不同的Task(Task可以动态⽣成),并根据Task之间的dependsOn,确定Task的执⾏顺序,或者禁⽤某些Task。此阶段完成后,Task之间的依赖关系也就确定下来。
(3)执⾏阶段
在配置完成后,按照依赖关系,按顺序执⾏。
需要注意的是通常在Task中的语句,都是在配置阶段执⾏的,⽽doFirst,doLast这类Action是在执⾏阶段中的。因此会出现你的依赖关系中没有的Task中语句也被执⾏了的问题
如下例⼦,打印出的task内容是不⼀样的
task printTasksName {
tasks.all {//all是⼀个⽅法,参数可以是闭包,函数的元括号可以省略
println "show tasks in Configuration:${it.name}" //it是闭包的默认参数
}
doFirst {
tasks.all {
println "show tasks in Execution:${it.name}"
}
}
}
4.Gradle插件和Androd插件
在提供了基本的流程控制之后,接下来是具体的要做什么,构建什么。Gradle提供了针对语⾔的插件如java,groovy等负责编译,集成插件如application,war等⽣成java可执⾏程序,web程序的WAR⽂件。Android根据APK⽣成的过程,编写了⾃⼰的插件,其中也使⽤了java插件。
(1)⾃定义插件的插件名称在resources/META-INF/gradle-plugins
在resources/META-INF/gradle-plugins⽬录下有后缀为properties⽂件,该⽂件的命名就是你在adle中使⽤插件的名字,⾥⾯声明了该插件的实现类。在Android插件的源码中可以看到android.properties和com.android.application.properties中两个插件名称,因此在adle中,应⽤⼯程使⽤Android插件需要apply plugin: 'android'(已是deprecated)或者apply plugin: 'com.android.application'
(2)Android插件中application的实现类是AppPlugin,继承⾃com.adle.BasePlugin ,调⽤apply⽅法,相应的configureProject(),解析local.properties,获得sdk位置,创建AndroidBuilder,应⽤JavaBasePlugin,⽽后createExtension() 关联BuildType,ProductFlavor,SigningConfig,最后createTasks(),完成各个Task的创建
5.DSL(Domain Specific Language)
DSL我翻译成领域专⽤语⾔,就是在这⾥预先规定好的规则,或者说是⾏话。在Gradle的DSL中⼀般常见的类型,⼀种是类型(Type)有Project、Task等,给他们定义了不同的操作和⽤法,⼀种是语句块(build script block或configuration block)如adle中常见的buildscript { },allprojects { }。Android中也定义了⾮常多语句块,如buildTypes { },sourceSets { }。Android Gradle插件配置
有了上述概念,再看android应⽤中的adle,其实⽂中也只能讲⼀些,但是更多的可以⾃⼰查看Android插件的DSL apply plugin: 'com.android.application' // 使⽤Android插件,⾮库⼯程,⽣成的是apk
dependencies {
compile 'com.android.support:multidex:1.0.1'
compile fileTree(dir: 'libs', include: '*.jar')
compile project(':库⼯程1') // 代码、资源包含在主程序apk中的
provided project(':库⼯程1') // 只参与编译,不输出到⽬标apk中
}
// Android插件DSL中的AppExtension类型
android {
pileSdkVersion // 多⼯程时配置统⼀的属性
buildToolsVersion
// lint检查,避免lint检测到不符合条件退出编译
lintOptions {
abortOnError false
}
// gradle编译会默认合并库⼯程的manifest到主⼯程,如果主程序和库⼯程的包名不⼀致会有问题
enforceUniquePackageName = false
// 所有的 product flavors继承
defaultConfig {
applicationId "cn.arainfo"
minSdkVersion 14
targetSdkVersion 10
// multiDexEnabled true
dexOptions {
javaMaxHeapSize "2g"
jumboMode true
}
}
// 此处由于⼯程是从Eclipse导⼊,所有路径都进⾏了声明
sourceSets {
main {
manifest.srcFile 'l'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
debug.setRoot('build-types/debug')
release.setRoot('build-types/release')
}
// 编译类型,指定release的proguard配置⽂件
buildTypes {
release {
minifyEnabled true
proguardFile 'proguard.flags'
}
}
免费论文下载网站大全}
afterEvaluate {
println "afterEvaluate set "
project(':主程序⼯程').ByName("assembleDebug").dependsOn ":⼦程序⼯程:assembleDebug"
if (project.hasProperty('TestRelease')) {
project(':主程序⼯程').ByName("assembleRelease").dependsOn ":⼦程序⼯程:assembleRelease"
}
}
说明⼏处
(1)如在根⽬录的adle中声明公⽤属性
ext {
compileSdkVersion = 21
buildToolsVersion = '25.0.0'
isOnWindows = Os.isFamily(Os.FAMILY_WINDOWS)
}
(2)buildTypes { },productFlavors{ },signingConfigs { }
上述三个语句块,类型是NamedDomainObjectContainer<T>,其中T是BuildType ProductFlavor SigningConfig,⽽buildTypes { },productFlavors{ }中增加新的类型,会对应有新的Task⽣成,规则为assemble[flavor][buildType],因此当compileSdkVersion较低,⼜⽤了MultiDex时,还想⽤InstantRun,就可以创建⼀个新的buildType,只在测试时使⽤
(3)afterEvaluate语句块
Android的Gradle插件版本在2.2.0时,Task的创建已经在afterEvaluate,因此,如果想继续使⽤
总结:
越写越⼼虚,零零碎碎的内容⾮常多,按照⾃⼰的理解贯穿下来,涵盖了部分内容,基本可以理解adle。但是语句块如buildTypes { }和BuildType如何关联起来(或者说如何解析出来并创建对象)的,并没有很好的理解。
如果有时间可以好好看下《深⼊理解Android(⼀):Gradle详解》,⼀般的问题,⽐如多渠道打包productFlavors怎么配置啊,⾃⼰通过查Android的DSL就能解决。
参考⽂档:
1.Groovy官⽅⽂档
2.Gradle⽤户⼿册
3.Gradle的DSL
4.Android插件的DSL
5.深⼊理解Android(⼀):Gradle详解
感谢阅读,希望能帮助到⼤家,谢谢⼤家对本站的⽀持!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论