理解使用Gradle编译打包Android apk

本篇的目的:理解Gradle构建过程,解读Android Gradle插件的配置

阅读本文一定是要使用过Gradle生成apk,文中不会讲如何安装运行Gradle,如有需要可先看文末的参考文章。

APK包是一个ZIP压缩包,从Java源代码、资源文件到生成这个APK,经过了编译打包一系列特定的过程,这个过程可以参看《使用Ant打包Android应用——apk生成过程》,也可以从自己的旧版SDK文档(/docs/tools/building/index.html)中找到。而这一系列特定的过程,重复繁琐,构建工具(build tool)就是来流程化这些过程,解放你的双手。Ant作为apk早期的构建工具,构建过程显得很直观,像配置;Gradle可以方便地配置,但更像脚本,可以编程。

理解Gradle构建

1.简单理解构建工具

从一个程序员的角度,你该如何编写代码来自动化你的apk生成过程呢?首先得知道你需要的SDK、NDK在什么位置,Android工程有几个库工程,它们的Java源代码、资源文件分别有哪些?命令行的输入参数肯定无法满足需求,那自然而然想到配置文件。因此你的自动化工具就是解析这些配置文件,按照生成apk文件要求执行的程序。Gradle就是这样的工具程序,配置文件就是你常见的settings.gradle,build.gradle,不过他还提供了更多的功能,如依赖管理,流程控制,还有插件机制来定制你的生成过程。

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的形式
assert colors.green == ‘#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实例,可以看到最新执行的是在settings.gradle中的语句

(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文件,该文件的命名就是你在build.gradle中使用插件的名字,里面声明了该插件的实现类。在Android插件的源码中可以看到android.properties和com.android.application.properties中两个插件名称,因此在build.gradle中,应用工程使用Android插件需要apply plugin: ‘android‘(已是deprecated)或者apply plugin: ‘com.android.application‘

(2)Android插件中application的实现类是AppPlugin,继承自com.android.build.gradle.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)如build.gradle中常见的buildscript { },allprojects { }。Android中也定义了非常多语句块,如buildTypes { },sourceSets { }。

Android Gradle插件配置

有了上述概念,再看android应用中的build.gradle,其实文中也只能讲一些,但是更多的可以自己查看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 {
  compileSdkVersion rootProject.ext.compileSdkVersion // 多工程时配置统一的属性
  buildToolsVersion rootProject.ext.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 ‘AndroidManifest.xml‘
  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 dependsOn..."
  project(‘:主程序工程‘).tasks.getByName("assembleDebug").dependsOn ":子程序工程:assembleDebug"

  if (project.hasProperty(‘TestRelease‘)) {
  project(‘:主程序工程‘).tasks.getByName("assembleRelease").dependsOn ":子程序工程:assembleRelease"

  }
}

说明几处

(1)如在根目录的build.gradle中声明公用属性

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,因此,如果想继续使用tasks.getByName("assembleDebug"),必须要将自己的语句写到afterEvaluate { }语句块中

总结:

越写越心虚,零零碎碎的内容非常多,按照自己的理解贯穿下来,涵盖了部分内容,基本可以理解build.gradle。但是语句块如buildTypes { }和BuildType如何关联起来(或者说如何解析出来并创建对象)的,并没有很好的理解。

如果有时间可以好好看下《深入理解Android(一):Gradle详解》,一般的问题,比如多渠道打包productFlavors怎么配置啊,自己通过查Android的DSL就能解决。

参考文档:

1.Groovy官方文档

2.Gradle用户手册

3.Gradle的DSL

4.Android插件的DSL

5.深入理解Android(一):Gradle详解

时间: 2024-10-13 22:25:47

理解使用Gradle编译打包Android apk的相关文章

Ant编译打包Android工程流程

一.Ant编译打包android工程步骤 二.Ant apk签名 1.keystore签名    定义自己的签名文件 生成keystore文件:keytool -genkey -alias android.keystore -keyalg RSA - validity 20000 -keystore android.keystore 对应的java命令:jarsigner -verbose -keystore android.keystore -signedjar android_signed.

cocos2d jsb 打包 Android APK

1.首先要会普通的cpp 打包成Android APK 以下所说的是在cocos2d-x 2.2.2 或者 2.3 版本中.本文在Eclipse总用ndk编译cocos2d-x. 老生常谈cocos2d-x JSB不是简单的js代码,涉及到C++代码,如果是Android的话又涉及到Java代码,有点复杂,如果搞过Android下的Jni的话会熟悉些.可以看下这篇文章:<Android Jni 例子 Hello JNI,ndk> Android为了提高开发者开发应用的速度,降低难度,选择了Ja

(转载)Ant自动编译打包android项目

1  Ant自动编译打包android项目 1.1   Ant安装 ant的安装比较简单,下载ant压缩包  http://ant.apache.org  (最新的为1.9.3版本),下载之后将其解压到某个目录(本人解压到E:\Program Files\apache-ant-1.9.3) ,然后配置环境变量(新建ANT_HOME环境变量,值为ant所在的目录,然后将ANT_HOME/bin添加到path中),如图: 打开命令行工具,输入 ant  -version ,如果出现如下结果,说明an

Jenkins Android gradle只能打包app-release-unsigned.apk

最近在通过jenkins自动打包安卓apk,但是测试打包的时候发现只能生成app-release-unsigned.apk,这个发到安卓手机因为缺少证书不能安装.解决办法是1.在app/build.gradle文件中增加signingConfigs字段 apply plugin: 'com.android.application' android { compileSdkVersion 21 buildToolsVersion "21.1.0" defaultConfig { appl

tomcat+Gradle全自动打Android apk包方案

最近看到公司IOS的同事做了一个app打包工具给QA使用,极大的方便了QA的工作,也给开发节省了不少精力,不需要频繁的接收QA的要求给QA打包新app做测试,防止编程思路被打包这些琐事给打断. 为了编写方便和跨平台应用,我使用了网页版的交互方式,使用tomcat 8做服务器,这样可以让任意一台手机和电脑通过浏览器就可以轻松的打包然后收到相应的.app文件,界面大概是这个样子 主要的功能是这样的 1.可以自由切换分支,分支号通过下拉列表的形式显示在网页上 2.可以自由切换服务器环境,比如测试服,开

Android-Ant自动编译打包android项目 -- 2 ----签名与渠道包

上篇介绍了怎么使用ant自动编译打包现有的android项目,这篇将继续介绍如果如何在ant打包应用的时候加入签名信息以及自动打包渠道包. 1. 加入签名信息: 在项目的根目录下建一个ant.properties文件,输入如下内容,其中keystore密码和alias密码可以不指定(防泄漏),那么在命令执行的过程中会要求你输入. [html] view plaincopy #keystore的路径,必须使用正斜杠 key.store=E:/wp_android_sample/me.key #ke

Ant自动编译打包android项目(转载)

1.1   Ant安装 ant的安装比较简单,下载ant压缩包  http://ant.apache.org  (最新的为1.9.3版本),下载之后将其解压到某个目录(本人解压到E:\Program Files\apache-ant-1.9.3) ,然后配置环境变量(新建ANT_HOME环境变量,值为ant所在的目录,然后将ANT_HOME/bin添加到path中),如图: 打开命令行工具,输入 ant  -version ,如果出现如下结果,说明ant 安装成功.  1.2   为Androi

图文来教你在eclipse下用gradle 来打包Android

gradle其他好处就不多说,在android应用发布的时候,如果要统计多个渠道,gradle 批量打包的好处就显示出来了:下面介绍图文来介绍 按eclipse的导出时 选择Android:如下图 然后按下面一步一步往下点 点击完成之后 工程里面就生成了如下的几个文件:也就是gradle的配置文件 打开gradle-wrapper.properties这个文件:可以看到distributionUrl这个地址:而这个地址就是gradle的下载地址:在浏览器打开下载 如下图: 将下载的文件押解出来:

使用Ant自动签名、打包Android apk并且自动安装到手机

一.建立Ant打包Apk 新建一个TestAnt项目 创建App的签名密钥 参考我的这篇github,欢迎Star|点击这里 取到密钥后,在项目中创建一个keystore的文件夹,复制密钥到此 给项目添加Ant //到项目的上级目录 cd /Users/.../Documents/workspace/ //给相聚添加ant,-p 项目 -t 是target 我这里是android-21 android update project -p TestAnt -t android-21 --subpr