前言
Android官网构建系统介绍https://developer.android.com/studio/build/index.html
Gradle 是 Android 现在主流的编译工具,虽然在Gradle 出现之前和之后都有对应更快的编译工具出现,但是 Gradle 的优势就在于它是亲儿子,Gradle 编译比较慢,这和它的编译过程有关,但是最近伴随着 Android Studio2.0的发布(目前官网最新gradle 为2.2.0), Gradle 也进行了一次非常大的升级,叫Instant Run.它的编译速度网上有人用逆天两个字来形容。(虽然目前有 Bug 我们要相信,他会好的)
对于一些比较复杂的,特别是多人团队合作的项目我们会需要一些个性化的配置来提高我们的开发效率。一些高级功能需要我们手动的去配置gradle脚本。
按官网流程一一介绍,有疏漏的请留言,我们一起学习
首先来张大图
对于一个典型的Android应用程序模块构建过程,遵循以下一般步骤:
- 编译器转换你的源代码转换成DEX(Dalvik的可执行文件)的文件,其中包括Android设备上运行的字节码,和其他一切编译资源。
- 该APK包装结合了DEX文件,资源编译成一个单一的APK。之前可以安装你的应用程序并部署到Android设备,但是,APK必须签名。
- 该APK打包签署使用Debug或发布密钥库您的APK:
a. 如果您正在构建您的应用程序,这是一个调试版本,应用程序你打算仅用于测试和分析后,打包签署您的应用程序与调试密钥库。Android Studio中自动配置与调试密钥库的新项目。
b. 如果您正在构建您的应用程序,你要在外部释放的发行版中,打包签署您的应用程序一起发布密钥库。要创建一个发布密钥库,了解Android Studio中签署您的应用程序。 - 产生最终的APK之前,打包使用zipalign工具来优化您的应用程序在设备上运行时,使用较少的内存。
在构建过程的最后,您有一张调试APK或释放您的应用程序,你可以用它来部署,测试或释放到外部用户的APK。
以上是官网对apk打包过程的一个简要概括,我们根据官网对gradle进行一个简单的介绍:
-
Build Types
定义了编译类型,针对每个类型我们可以有不同的编译配置,不同的编译配置对应的有不同的编译命令。默认的有debug、release 的类型。
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
applicationIdSuffix ".debug"
}```
2. *Product Flavors*
如果我们需要针对同一份源码编译不同的程序(包名也不同),比如 免费版和收费版。我们就需要Product flavors。
注意,**Product flavors**和**Build Type**是不一样的,而且他们的属性也不一样。**所有的 product flavor 版本和defaultConfig 共享所有属性!**
像Build type 一样,product flavor 也可以有自己的source set
文件夹。除此之外,product flavor 和 build type 可以结合,他们的文件夹里面的文件优先级甚至高于 单独的built type 和product flavor 文件夹的优先级。如果你想对于 blue类型的release 版本有不同的图标,我们可以建立一个文件夹叫blueRelease
,注意,这个顺序不能错,一定是 flavor+buildType 的形式。
productFlavors {
demo {
applicationId "com.example.myapp.demo"
versionName "1.0-demo"
}
full {
applicationId "com.example.myapp.full"
versionName "1.0-full"
}
}```
-
Build Variants
在开发中我们可能会有这样的需求:
-- 我们需要在debug 和 release 两种情况下配置不同的服务器地址;
-- 当打市场渠道包的时候,我们可能需要打免费版、收费版,或者内部版、外部版的程序。
-- 渠道首发包通常需要要求在欢迎页添加渠道的logo。等等
-- 为了让市场版和debug版同时存在与一个手机,我们需要编译的时候自动给debug版本不一样的包名。
这些需求都需要在编译的时候动态根据当前的编译类型输出不同样式的apk文件。这时候就是我们的buildType大展身手的时候了。 -
Manifest Entries
您可以在构建变量的配置清单文件的一些属性的值。这些构建值清单文件覆盖现有值。如果您想为您的模块,其中每个APK文件有不同的应用程序名称,最小的SDK版本,或目标SDK版本多个APK这是非常有用的。
defaultConfig {
/**
* applicationId uniquely identifies the package for publishing.
* However, your source code should still reference the package name
* defined by the package attribute in the main/AndroidManifest.xml file.
*/
applicationId 'com.example.myapp'
// Defines the minimum API level required to run the app.
minSdkVersion 14
// Specifies the API level used to test the app.
targetSdkVersion 23
// Defines the version number of your app.
versionCode 1
// Defines a user-friendly version name for your app.
versionName "1.0"
}
-
Dependencies
构建系统管理从本地文件系统,并从远程仓库项目的依赖。这可以使您不必手动搜索,下载和你的依赖的二进制包拷贝到你的项目目录 。这里提供下marven仓库的搜索地址:http://search.maven.org/ 不用翻墙也可以的哦
android {...}
...
dependencies {
// The 'compile' configuration tells Gradle to add the dependency to the
// compilation classpath and include it in the final package.
// Dependency on the "mylibrary" module from this project
compile project(":mylibrary")
// Remote binary dependency
compile 'com.android.support:appcompat-v7:23.4.0'
// Local binary dependency
compile fileTree(dir: 'libs', include: ['*.jar'])
}```
6. *Signing*
如果我们打包市场版的时候,我们需要输入我们的keystore数据。如果是debug 版本,系统默认会帮我们配置这些信息,秘钥在home/.android/debug.keystore。这些信息在gradle 中都配置在signingConfigs中。
android {
signingConfigs {
config {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
}
...
}```
-
ProGuard
构建系统使您可以指定每个构建变量不同ProGuard的规则文件。构建系统可以运行ProGuard的构建过程中缩小和模糊处理的类。说白了,就是在gradle中进行混淆配置
android {
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile(‘proguard-android.txt'),
'proguard-rules.pro'
}
}
...
}
Note: Android Studio disables ProGuard when using Instant Run.
-
APK Splits
构建系统可以自动建立不同的APK,每个只包含代码,需要一个特定的屏幕密度或应用程序二进制接口(ABI)的资源。
android {
...
splits {
// Configures screen density split settings
density {
// Enables density APK splits
enable true
// Specifies a list of screen densities Gradle should not create APK splits for
exclude "ldpi", "xxhdpi", "xxxhdpi"
// Specifies a list of compatible screen size settings for the manifest
compatibleScreens 'small', 'normal', 'large', 'xlarge'
}
}
}```
当启动一个新的项目,Android的Studio会自动创建一些这些文件对你来说,并填充它们基于合理的默认值。
![Paste_Image.png](https://img.haomeiwen.com/i2333435/055d48c44da3a35d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
1. The Gradle Settings File
2. The Top-level Build File
3. The Module-level Build File
4. Gradle Properties Files
目录结构及gradle详细说明官网都说的很清晰
https://developer.android.com/studio/build/index.html#build-files, 掌握了以上的基本结构和基本写法,简单的Android工程构建基本上不会有什么问题了
有gradle语法不了解的童鞋可直接查看官网代码
https://docs.gradle.org/current/userguide/userguide.html 很庞大知识体系,接下来我们稍微了解一些与Android相关的gradle进阶应用
Gradle脚本不是像传统的xml文件那样,而是一种基于Groovy的动态DSL,而Groovy语言是一种基于jvm的动态语言。
**Project和tasks**
在grade中的两大重要的概念,分别是project和tasks。每一次构建都是有至少一个project来完成,所以Android studio中的project和Gradle中的project不是一个概念。每个project有至少一个tasks。每一个build.grade文件代表着一个project。tasks在build.gradle中定义。当初始化构建进程,gradle会基于build文件,集合所有的project和tasks,一个tasks包含了一系列动作,然后它们将会按照顺序执行,一个动作就是一段被执行的代码,很像Java中的方法。
**构建的生命周期**
一旦一个tasks被执行,那么它不会再次执行了,不包含依赖的Tasks总是优先执行,一次构建将会经历下列三个阶段:
![Paste_Image.png](https://img.haomeiwen.com/i2333435/b97b3d94a96a5439.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
生命周期事件可以在指定的生命周期之前、之中或者之后发生,在执行阶段之后发生的生命周期事件就该是构建的完成了。假设你希望在构建失败时能够在开发阶段尽早得到反馈,给构建生命周期事件添加回调有两种方法:一是通过闭包,二是实现Gradle API的一个监听接口,Gradle并没有要求你监听生命周期事件,这完全决定于你,通过监听器实现的优势就是可以给你的类写单元测试,看看下面这幅图会有一点直观的印象:
![Paste_Image.png](https://img.haomeiwen.com/i2333435/6fbe195faa0feab4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
在配置阶段,Gradle决定在任务在执行阶段的执行顺序,依赖关系的内部结构是通过直接的无环图(DAG)来表示的,图中的每一个任务称为一个节点,每一个节点通过边来连接,你很有可能通过dependsOn或者隐式的依赖推导来创建依赖关系。记住DAG图从来不会有环,就是说一个已经执行的任务不会再次执行,下面这幅图将要的展示了这个过程:
![](https://lippiouyang.gitbooks.io/gradle-in-action-cn/content/images/dag28.png)
**项目结构**
和eclipse对比来看,Android studio构建的结构有很大的不同:
MyApp
├── build.gradle
├── settings.gradle
└── app
├── build.gradle
├── build
├── libs
└── src
└── main
├── java
│ └── com.package.myapp
└── res
├── drawable
├── layout
└── etc.
gradle使用了一个叫做source set的概念,官方解释:一个source set就是一系列资源文件,其将会被编译和执行。对于Android项目,main就是一个source set,其包含了所有的资源代码。当你开始编写测试用例的时候,你一般会把代码放在一个单独的source set,叫做androidTest,这个文件夹只包含测试。(此处不做测试开发可以不用了解)
***使用Gradle Wrappe防止新版本迭代所导致的问题***
grade只是一个构建工具,而新版本总是在更迭,所以使用Gradle Wrapper将会是一个好的选择去避免由于gradle版本更新导致的问题。Gradle Wrapper提供了一个windows的batch文件和其他系统的shell文件,当你使用这些脚本的时候,当前gradle版本将会被下载,并且会被自动用在项目的构建,所以每个开发者在构建自己app的时候只需要使用Wrapper。所以开发者不需要为你的电脑安装任何gradle版本,在mac上你只需要运行gradlew,而在windows上你只需要运行gradlew.bat。
在目录指定gradle插件版本
dependencies { classpath 'com.android.tools.build:gradle:1.2.3' }
,在项目的gradle/wrapper目录下面有个gradle-wrapper.properties中有如下内容:
distributionUrl=https://services.gradle.org/distributions/gradle-2.2.1-all.zip```
修改URL也可以对gralde插件版本的控制。
关于gradle具体用法,我们后续再更新,gradle用法太杂,我们慢慢梳理 😜
关注微信公众号 Android历练记 或扫一扫二维码:
让我们一起来搞事情。
网友评论