百度APP技术团队教你Android:Gradle 与 Android 构建入门(1)

.gradle 与 .idea

.gradle 与 .idea 存放 Gradle 和 AS 对于当前工程的缓存。

最常见的一个应用就是点击 sync 后,AS 会在每个工程下生成 .iml 文件,他们与 .gradle、.idea 配合为我们提供了代码提示等常见功能。所以如果你的代码飘红而你确认依赖没有问题,可以尝试下面步骤清除 AS 缓存:

  • 删.idea 删.gradle 文件

  • 命令行执行 ./gradlew clean

  • 选择 File -> invalidate caches/restart

  • Sync

gradle/wrapper 与 gradlew gradlew.bat

当我们初次配置 Android 环境时,需要安装 Java,安装 AS,但并不需要安装 Gradle,这其中就是 gradle/wrapper 的功劳。

当执行 gradlew 脚本时,它可以保证每个项目都使用自己期望的 Gradle 版本,而其中的奥秘就在 gradlew 的这段代码中

exec “ J A V A C M D " " JAVACMD" " JAVACMD""{JVM_OPTS[@]}” -classpath “ C L A S S P A T H " o r g . g r a d l e . w r a p p e r . G r a d l e W r a p p e r M a i n " CLASSPATH" org.gradle.wrapper.GradleWrapperMain " CLASSPATH"org.gradle.wrapper.GradleWrapperMain"@”

gradlew 并没有直接启动 Gradle 而是启动 gradle-wrapper.jar,它会判断如果没有 Gradle 环境,从 gradle-wrapper.properties 中的 distributionUrl 中下载相应环境,并启动 Gradle。

因为 Gradle 允许命令行启动时附加参数来自定义 Gradle 的运行环境,所以百度app通过自定义 gradle-wrapper.jar,实现通过配置文件为不同内存大小的电脑、debug/release 包指定不同 gradle 运行内存,提升大家编译速度。

setting.gradle

在这里插入图片描述

setting.gradle 中最关键的就是其提供的 include 方法,通过这个方法可以指定哪些工程需要参与编译,每一个参与编译的工程 Gradle 会为它创建一个 Project 对象

根目录 build.gradle

在这里插入图片描述

首先是 buildscript 代码块: gradle 默认是自顶向下执行,无论 buildscript 代码块在哪,它都会第一个执行

接下来是 repositories 和 dependencies: repositories 表示 dependencies 声明的依赖去哪些仓库找,google、jcenter、mavenCentral 都是第三方 Maven 仓库。同时,也可以通过 maven 方法添加自己的 Maven 仓库。需要注意的是,不应该假设组件一定会从特定仓库拉取,如果 Gradle 请求一个仓库超时,它会自动请求其他仓库。

dependencies:代表 Gradle 执行需要哪些依赖。比如需要 Android Gradle Plugin 插件为我们打包 apk 包,就需要添加: classpath ‘com.android.tools.build:gradle:3.4.0’

最后是 allprojects 和 repositories: 在 allprojects 中的配置会对所有工程生效而里面的 repositories 则表示工程声明的 dependencies 去哪些仓库查找

app build.gradle

在这里插入图片描述

首先可以看到 apply plugin: ‘com.android.application’,当应用这个插件后,它会为我们创建一系列 Task,比如 assembleDebug、assembleRelease,执行这些 Task,就会得到最终的 APK。

android 代码块是插件为我们提供的 API允许我们修改 Task 的行为。

dependencies 代码块的内容决定当前 Project 依赖哪些组件,而不同的依赖声明会有不同的结果,具体内容我们在下一节分析。

依赖管理


依赖配置

在 Android Gradle Plugin 3.0 时代,Google 使用 implementation 和 api 选项取代过去的 compile 选项。既然接口都变了,Google 索性将其他的配置项也进行了改名,方便大家理解其配置的含义。需要注意的是,老版本的接口没有被立刻删除,但是在下一个主要版本中会被删除。下面是各个配置项的官方中文解释:

在这里插入图片描述

举个例子: 假设 A 依赖 B,B 依赖 C。

如果 B 对 C 使用 implementation 依赖,则 A 无法调用 C 的代码

如果 B 对 C 使用 api 依赖,则 A 可以调用 C 的代码

如果 B 对 C 使用 compileOnly 依赖,则 A 无法调用 C 的代码,且 C 的代码不会被打包到 APK 中

如果 B 对 C 使用 runtimeOnly 依赖,则 A、B 无法调用 C 的代码,但 C 的代码会被打包到 APK 中

实际上每一个组件都有自己的 compileClasspath 和 runtimeClasspath

当一个组件参与编译时,Gradle 就会将其放在 compileClasspath 中

当一个组件参与打包时,Gradle 就会将其放在 runtimeClasspath 中

不同的依赖配置项,其实就是将声明的依赖放入不同组件的不同的 classpath 中,回到上面的例子 对于 implementation ,其实就是将 C 放入 B 的 compileClasspath 和 runtimeClasspath,放入 A 的 runtimeClasspath 中,从而实现 A 如果调用 C 的代码,在 A 的编译阶段 javac 报错,但最终 C 会被打包到 APK 包中

对于 api、compileOnly、runtimeOnly 原理相同

源码与二进制

当想要依赖一个源码工程时只需要这样写: implementation project(’:demo:mylibrary’)

而且我们可以明确知道 mylibrary 中的依赖都会被正确打包到 APK 中

当我们依赖二进制需要这样写: implementation ‘androidx.appcompat:appcompat:1.0.2’

当执行依赖命令(只输出 release 包的 runtimeClasspath):

./gradlew :app:dependencies --configuration releaseRuntimeClasspath > dependencies.txt

输出依赖关系图时会看到并不是仅仅依赖一个 appcompat 组件(只显示部分依赖),还包含该组件自己的依赖,以及依赖的依赖,直到组件自身没有依赖,这样的特性叫做依赖传递

releaseRuntimeClasspath - Resolved configuration for runtime for variant: release

— androidx.appcompat:appcompat:1.0.2

±-- androidx.annotation:annotation:1.0.0

±-- androidx.core:core:1.0.1

| ±-- androidx.annotation:annotation:1.0.0

| ±-- androidx.collection:collection:1.0.0

| | — androidx.annotation:annotation:1.0.0

| ±-- androidx.lifecycle:lifecycle-runtime:2.0.0

| | ±-- androidx.lifecycle:lifecycle-common:2.0.0

| | | — androidx.annotation:annotation:1.0.0

| | ±-- androidx.arch.core:core-common:2.0.0

| | | — androidx.annotation:annotation:1.0.0

| | — androidx.annotation:annotation:1.0.0

| — androidx.versionedparcelable:versionedparcelable:1.0.0

| ±-- androidx.annotation:annotation:1.0.0

| — androidx.collection:collection:1.0.0 (*)

±-- androidx.collection:collection:1.0.0 (*)

±-- androidx.cursoradapter:cursoradapter:1.0.0

那么 Gradle 是怎么确定这些依赖呢?当使用Maven 规范上传组件时,不单单会上传组件的二进制,还会上传一个 pom.xml 文件,依赖信息就在这个文件当中。

因为查看公共的 Maven 服务器有可能需要翻墙,下面给大家展示百度app自己搭建的服务器的后台,方便理解被上传的二进制在服务器是以怎样的结构存放的

在这里插入图片描述

这个是百度app自己搭建的 Maven 服务器后台,点击一项查看详情:

在这里插入图片描述

有上传的二进制 aar,也有 pom 文件,还有我们在上传时自定义的文件 readme

看完远端的 POM 文件,我们在看看当二进制被下载后在本地是如何存放的

在这里插入图片描述

下面是一个简单的 POM 文件:

在这里插入图片描述

可以看到有两个 dependency,需要注意的是 scope,也会分为 runtime 和 compile,runtime 不会参与编译,但会参与打包,compile 会参与编译和打包

两个实际例子: 一:假设 A 依赖 B,B 依赖 C

在这里插入图片描述

B 对 C 使用 implementation 依赖

B 中有类 Foo 继承于 C中的 Bar

在 A 中使用类 Foo 时会报错找不到类 Bar,解决办法只能让 A 再依赖 C,所以应该尽量避免使用继承

二:假设 A 依赖 B,B 依赖 C

BC 是二进制, B 的 POM 中对 C 的依赖是 runtime

在 Gradle 4.4 中,A 依然可以调用 C 的代码,这个问题在 Gradle 5.0 后被修复

依赖冲突

什么是依赖冲突:

在这里插入图片描述

假设 ABC 是源码,D 是二进制,A 声明依赖 B,A 声明依赖 C,B 声明依赖 D 1.0 版本,C 声明依赖 D 1.1版本,这时,D 有依赖冲突,需要确定是使用 1.0 还是 1.1 版本

如何解决依赖冲突:

  1. 进行编译时,B 编译时依赖 D 的1.0版本,C 编译时依赖 D 的1.1版本,但最终打包到 apk 中 D 的版本是 1.1,因为版本号冲突默认选择最高版本

  2. Gradle 为我们提供了一系列解决依赖冲突的规则如:不允许依赖传递,exclude 移除一个依赖,替换一个组件为另一个组件,这些方法就不一一介绍了,按需百度即可

  3. 百度app在此基础上增加规则:如果最终应用的版本号高于在 version.properties 定义的版本号则报错

注意:

  1. 假设 D 发布 1.2 版本,但 B、C 都没有基于 D 1.2 版本发布新版本,则最终打包还是 D 的 1.1 版本,所以所有组件最终被打包到 APK 包中的版本都为 version.properties 中定义的版本

  2. 假设 D 的 MavenId 由 D 改成了 E,C 基于 E 发布二进制,B 还是老样子,在实际打包中会报类重复的错误,原因就是 B 的 POM 文件中依赖的还是 D,所以需要让 B 基于 D 改名后的 E重新发一个二进制

打包流程 有了前面这些铺垫,让我们实际看看在执行打包 Task 时,实际还执行了哪些 Task。环境配置如下:

Gradle 5.1.1

Android Gradle Plugin 3.1.2

org.gradle.parallel=true 开启并行编译

release 包 minifyEnabled true

执行命令可以得到如下图所示输出

–dry-run 表示不实际执行每个 Task

gradlew assembleRelease --dry-run

在这里插入图片描述

Task 很多,接下来为大家介绍几个重点的 Task,其余没介绍的感兴趣的同学可以找找对应的实现类,看看它的实现。

preBuild

描述:做一些编译前的检查

一个例子:有的人可能遇到下面的错误

"Android dependency "+ display+ “is set to compileOnly/provided which is not supported”

学习分享

在当下这个信息共享的时代,很多资源都可以在网络上找到,只取决于你愿不愿意找或是找的方法对不对了

很多朋友不是没有资料,大多都是有几十上百个G,但是杂乱无章,不知道怎么看从哪看起,甚至是看后就忘

如果大家觉得自己在网上找的资料非常杂乱、不成体系的话,我也分享一套给大家,比较系统,我平常自己也会经常研读。

2021最新上万页的大厂面试真题

七大模块学习资料:如NDK模块开发、Android框架体系架构…

只有系统,有方向的学习,才能在段时间内迅速提高自己的技术。

这份体系学习笔记,适应人群:
**第一,**学习知识比较碎片化,没有合理的学习路线与进阶方向。
**第二,**开发几年,不知道如何进阶更进一步,比较迷茫。
**第三,**到了合适的年纪,后续不知道该如何发展,转型管理,还是加强技术研究。

由于文章内容比较多,篇幅不允许,部分未展示内容以截图方式展示 。

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
1最新上万页的大厂面试真题**

[外链图片转存中…(img-m23IyN07-1715344279308)]

七大模块学习资料:如NDK模块开发、Android框架体系架构…

[外链图片转存中…(img-4hkRUJpG-1715344279309)]

只有系统,有方向的学习,才能在段时间内迅速提高自己的技术。

这份体系学习笔记,适应人群:
**第一,**学习知识比较碎片化,没有合理的学习路线与进阶方向。
**第二,**开发几年,不知道如何进阶更进一步,比较迷茫。
**第三,**到了合适的年纪,后续不知道该如何发展,转型管理,还是加强技术研究。

由于文章内容比较多,篇幅不允许,部分未展示内容以截图方式展示 。

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值