Android项目构建Gradle专栏——build基础
目录:
- 构建体系
- Build流程
- 工具
- build文件分析
- gradle Task
- 依赖
公众号: https://mp.weixin.qq.com/s/WkwgKyAachnfCxKw3b1BMg
gradle专栏地址: https://gongshijier.github.io/2021/04/02/Android%E9%A1%B9%E7%9B%AE%E6%9E%84%E5%BB%BAGradle%E4%B8%93%E6%A0%8F%E2%80%94%E2%80%94build%E5%9F%BA%E7%A1%80/
1. 构建体系
Android 构建系统会编译应用资源和源代码,然后将它们打包成可供您测试、部署、签署和分发的 APK。
也就是说 构建: 从代码和应用资源到APK的过程
Android 采用的构建系统是 Gradle 工具, Android 项目架构中的一些和构建相关的文件就是供Gradle构建核心文件
- build.gradle
- settings.gradle
- app/build.gradle
- app/build.gradle
通过这些文件执行一系列的 Gradle Task 就完成从源代码和资源文件 ----> APK
参考下面的 project 目录, 项目中会有多个 module 每个module 内也都有 build.gradle 来负责构建事宜
2. Build流程
- 从需要构建的模块开始, 确定依赖项
- 编译
- 打包
编译器: 源代码 --> dex 文件
打包: 将dex和编译后的资源 组合为 apk 文件 并且使用相应的密钥库来进行签名
生成最终 APK 前, zipalign 会对APK进行一定优化, 减少内存占用
3. 工具
gradle 构建都是通过 gradle 构建工具包实现的
可以到 sdk目录: Library/Android/sdk/版本/build-tools 下找到对应的工具
构建过程就是通过gradle脚本使用这些工具, 完成前面说的 编译和打包和优化 图片引用
图片里面很清楚的说明了构建过程的各个核心流程
- aapt (Android asset package tool) :负责将xml文件和其他一些资源文件res ... 编译打包应用资源形成供代码访问的一个索引表
- aidl: 处理使用AIDL规范写的aidl文件, 编译为 java 源代码
- javac: java --> class 文件
- d8: class 文件 --> dex 文件
- zipalign: 字节码对齐工具, 进行优化, 类似垃圾回收标记整理的过程
- jarsigner: 使用密钥证书 为 apk 签名
对以上构建工具建议查阅官方资料: https://developer.android.com/studio/command-line?hl=zh-cn
4. build文件分析
settings.gradle
settings.gradle 文件位于项目的根目录下,用于指示 Gradle 在构建应用时应将哪些模块包含在内。
比如开源项目bytex settings.gradle 指明了哪些模块参与构建
//opensource
include ':shrink-r-plugin'
include ':access-inline-plugin'
include ':getter-setter-inline-plugin'
include ':refer-check-plugin'
include ':closeable-check-plugin'
include ':serialization-check-plugin'
include ':const-inline-plugin'
include ':field-assign-opt-plugin'
include ':method-call-opt-plugin'
include ':SourceFileKiller'
include ':butterknife-check-plugin'
include ':coverage-plugin'
project(':coverage-plugin').projectDir = new File('coverage/coverage-plugin')
include ':coverage-lib'
project(':coverage-lib').projectDir = new File('coverage/coverage-lib')
project/build.gradle
/**
* The buildscript block is where you configure the repositories and
* dependencies for Gradle itself—meaning, you should not include dependencies
* for your modules here. For example, this block includes the Android plugin for
* Gradle as a dependency because it provides the additional instructions Gradle
* needs to build Android app modules.
*/
buildscript {
/**
* The repositories block configures the repositories Gradle uses to
* search or download the dependencies. Gradle pre-configures support for remote
* repositories such as JCenter, Maven Central, and Ivy. You can also use local
* repositories or define your own remote repositories. The code below defines
* JCenter as the repository Gradle should use to look for its dependencies.
*
* New projects created using Android Studio 3.0 and higher also include
* Google's Maven repository.
*/
repositories {
google()
jcenter()
}
/**
* The dependencies block configures the dependencies Gradle needs to use
* to build your project. The following line adds Android plugin for Gradle
* version 4.1.0 as a classpath dependency.
*/
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
}
}
/**
* The allprojects block is where you configure the repositories and
* dependencies used by all modules in your project, such as third-party plugins
* or libraries. However, you should configure module-specific dependencies in
* each module-level build.gradle file. For new projects, Android Studio
* includes JCenter and Google's Maven repository by default, but it does not
* configure any dependencies (unless you select a template that requires some).
*/
allprojects {
repositories {
google()
jcenter()
}
}
- repositories: 指明依赖项目从哪里来, 从哪个仓库导入进来
- dependencies: 指明具体的 groupID 和 ArtifactID 用来找到具体依赖库
- buildScript: 这里的依赖是 Gradle 构建时候需要用的, 比如依赖一些库,需要使用他们定义的Gradle插件
重点注意 buildScript是 Gradle 需要的库, 比如一些 gradle plugin
比如:
buildscript {
repositories {
maven { url 'https://jitpack.io' }
maven {
url uri('../gradle_plugins')
}
google()
jcenter()
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath "com.android.tools.build:gradle:$gradle_version"
//依赖了 com.github.dcendents:android-maven-gradle-plugin 是因为gradle构建阶段需要使用到其内的插件
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0'
}
}
// 因为在 buildScript 中 , classpath 依赖了库, 所以可以在项目中可以使用 该 plugin
apply plugin: 'com.github.dcendents.android-maven'
buildscript {...}
allprojects {...}
// This block encapsulates custom properties and makes them available to all
// modules in the project.
ext {
// The following are only a few examples of the types of properties you can define.
compileSdkVersion = 28
// You can also create properties to specify versions for dependencies.
// Having consistent versions between modules can avoid conflicts with behavior.
supportLibVersion = "28.0.0"
...
}
...
全局 build.gradle 中的 ext 里面定义的一些 变量是全局可用的, 可以在其他模块中访问如:
android {
// Use the following syntax to access properties you defined at the project level:
// rootProject.ext.property_name
compileSdkVersion rootProject.ext.compileSdkVersion
...
}
...
dependencies {
implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
...
}
module/build.gradle
模块下的 build.gradle 配置则是 对该模块生效的一些特性
/**
* The first line in the build configuration applies the Android plugin for
* Gradle to this build and makes the android block available to specify
* Android-specific build options.
*/
apply plugin: 'com.android.application'
/**
* The android block is where you configure all your Android-specific
* build options.
*/
android {
/**
* compileSdkVersion specifies the Android API level Gradle should use to
* compile your app. This means your app can use the API features included in
* this API level and lower.
*/
compileSdkVersion 28
/**
* buildToolsVersion specifies the version of the SDK build tools, command-line
* utilities, and compiler that Gradle should use to build your app. You need to
* download the build tools using the SDK Manager.
*
* This property is optional because the plugin uses a recommended version of
* the build tools by default.
*/
buildToolsVersion "29.0.2"
/**
* The defaultConfig block encapsulates default settings and entries for all
* build variants, and can override some attributes in main/AndroidManifest.xml
* dynamically from the build system. You can configure product flavors to override
* these values for different versions of your app.
*/
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 15
// Specifies the API level used to test the app.
targetSdkVersion 28
// Defines the version number of your app.
versionCode 1
// Defines a user-friendly version name for your app.
versionName "1.0"
}
/**
* The buildTypes block is where you can configure multiple build types.
* By default, the build system defines two build types: debug and release. The
* debug build type is not explicitly shown in the default build configuration,
* but it includes debugging tools and is signed with the debug key. The release
* build type applies Proguard settings and is not signed by default.
*/
buildTypes {
/**
* By default, Android Studio configures the release build type to enable code
* shrinking, using minifyEnabled, and specifies the default Proguard rules file.
*/
release {
minifyEnabled true // Enables code shrinking for the release build type.
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
/**
* The productFlavors block is where you can configure multiple product flavors.
* This allows you to create different versions of your app that can
* override the defaultConfig block with their own settings. Product flavors
* are optional, and the build system does not create them by default.
*
* This example creates a free and paid product flavor. Each product flavor
* then specifies its own application ID, so that they can exist on the Google
* Play Store, or an Android device, simultaneously.
*
* If you declare product flavors, you must also declare flavor dimensions
* and assign each flavor to a flavor dimension.
*/
flavorDimensions "tier"
productFlavors {
free {
dimension "tier"
applicationId 'com.example.myapp.free'
}
paid {
dimension "tier"
applicationId 'com.example.myapp.paid'
}
}
/**
* The splits block is where you can configure different APK builds that
* each contain only code and resources for a supported screen density or
* ABI. You'll also need to configure your build so that each APK has a
* different versionCode.
*/
splits {
// Settings to build multiple APKs based on screen density.
density {
// Enable or disable building multiple APKs.
enable false
// Exclude these densities when building multiple APKs.
exclude "ldpi", "tvdpi", "xxxhdpi", "400dpi", "560dpi"
}
}
}
/**
* The dependencies block in the module-level build configuration file
* specifies dependencies required to build only the module itself.
* To learn more, go to Add build dependencies.
*/
dependencies {
implementation project(":lib")
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation fileTree(dir: 'libs', include: ['*.jar'])
}
- compileSdkVersion 28 用来编译的 Android API 版本
- buildToolsVersion "29.0.2" 用来 build 构建的 build-tools 版本
local.properties
系统本地环境属性
gradle.properties
配置一些全局的配置, 和 ext 闭包一样 可以在其他gradle文件中获得其中配置
5. gradle Task
gradle 执行的是一个个 task
gradle 开发的自定义plugin 也就是重写 apply 方法部分
每一次 Android 项目构建执行会执行一系列的gradle task 来完成整个构建过程比如:
可以参考该文章: https://mp.weixin.qq.com/s/6Cb6MqV9GQG60hBltss61A :
Starting Gradle Daemon...
Gradle Daemon started in 902 ms
> Task :app:preBuild UP-TO-DATE
> Task :app:preDebugBuild UP-TO-DATE
> Task :app:compileDebugAidl NO-SOURCE
> Task :app:compileDebugRenderscript NO-SOURCE
> Task :app:generateDebugBuildConfig UP-TO-DATE
> Task :app:checkDebugAarMetadata UP-TO-DATE
> Task :app:generateDebugResValues UP-TO-DATE
> Task :app:generateDebugResources UP-TO-DATE
> Task :app:mergeDebugResources UP-TO-DATE
> Task :app:createDebugCompatibleScreenManifests UP-TO-DATE
> Task :app:extractDeepLinksDebug UP-TO-DATE
> Task :app:processDebugMainManifest
> Task :app:processDebugManifest
> Task :app:javaPreCompileDebug UP-TO-DATE
> Task :app:mergeDebugNativeDebugMetadata NO-SOURCE
> Task :app:mergeDebugShaders UP-TO-DATE
> Task :app:compileDebugShaders NO-SOURCE
> Task :app:generateDebugAssets UP-TO-DATE
> Task :app:mergeDebugAssets UP-TO-DATE
> Task :app:compressDebugAssets UP-TO-DATE
> Task :app:processDebugJavaRes NO-SOURCE
> Task :app:mergeDebugJniLibFolders UP-TO-DATE
> Task :app:mergeDebugNativeLibs UP-TO-DATE
> Task :app:stripDebugDebugSymbols NO-SOURCE
> Task :app:validateSigningDebug UP-TO-DATE
> Task :app:mergeLibDexDebug
> Task :app:processDebugManifestForPackage
> Task :app:processDebugResources
> Task :app:compileDebugKotlin UP-TO-DATE
> Task :app:compileDebugJavaWithJavac UP-TO-DATE
> Task :app:compileDebugSources UP-TO-DATE
> Task :app:mergeDebugJavaResource UP-TO-DATE
> Task :app:dexBuilderDebug
> Task :app:mergeExtDexDebug
> Task :app:mergeProjectDexDebug
> Task :app:packageDebug
> Task :app:assembleDebug
BUILD SUCCESSFUL in 22s
27 actionable tasks: 10 executed, 17 up-to-date
//aidl 转换aidl文件为java文件
> Task :app:compileDebugAidl
//生成BuildConfig文件
> Task :app:generateDebugBuildConfig
//获取gradle中配置的资源文件
> Task :app:generateDebugResValues
// merge资源文件
> Task :app:mergeDebugResources
// merge assets文件
> Task :app:mergeDebugAssets
> Task :app:compressDebugAssets
// merge所有的manifest文件
> Task :app:processDebugManifest
//AAPT 生成R文件
> Task :app:processDebugResources
//编译kotlin文件
> Task :app:compileDebugKotlin
//javac 编译java文件
> Task :app:compileDebugJavaWithJavac
//转换class文件为dex文件
> Task :app:dexBuilderDebug
//打包成apk并签名
> Task :app:packageDebug
可以自己run apk 的时候看一下build 窗口中的一系列 gradle task执行过程
gradle task 是 gradle 流水线执行的节点
开发中 会针对一些 特定位置运行gradle task
比如很多 task 是有依赖关系的, 比如 你可以让 taskA , 依赖 taskB
也可以在buid结束时候添加一些 task
可以参考: https://blog.csdn.net/ccpat/article/details/89342198简单介绍了一些task
6. 依赖
开发中经常接触到就是处理库之间的依赖关系
常见的依赖方式:
apply plugin: 'com.android.application'
android { ... }
dependencies {
// Dependency on a local library module
implementation project(":mylibrary")
// Dependency on local binaries
implementation fileTree(dir: 'libs', include: ['*.jar'])
// Dependency on a remote binary
implementation 'com.example.android:app-magic:12.3'
}
里面代表了三种依赖源
本地模块、 jar包、 远程maven仓库
除了依赖源头, 依赖的方式也很多:
- implementation
- api
- compileOnly
- runtimeOnly
- annotationProcessor
Android项目构建gradle专栏系列持续更新中......
参考:
https://developer.android.google.cn/studio/build/index.html
https://mp.weixin.qq.com/s/6Cb6MqV9GQG60hBltss61A
https://cloud.tencent.com/developer/article/1392511
https://www.jianshu.com/p/e73510605c56
https://developer.android.com/studio/build?hl=zh-cn