技术标签: gradle ProjectApi Gradle Android
gradle 是一个基于 Apache Ant 和 Apache Maven 概念的项目自动化构建工具,他使用一种 基于 groovy 的特定领域语言来声明项目的设置,而不是使用传统的 XML 。gradle 就是工程的管理,帮我们做好了依赖,打包,部署,发布,各种渠道的差异管理等工作
gradle 完全使用的是 groovy 的语法。
非常灵活,可以自行去扩展。一款最新的构建工具,使用它逼格更高。丰富的第三方插件,项目构建灵活性更高,Maven ,Ant 能做的 Gradle 都能做,Gradle 能做的 它们不一定能做
Gradle 生命周期回调方法的时机:
/**
* 配置阶段开始前回调监听
*/
this.beforeEvaluate {
}
/**
* 配置阶段完成后回调监听
*/
this.afterEvaluate {
println '配置阶段完成...'
}
/**
* build 执行完毕
*/
this.buildFinished {
}
/**
* 监听 task 的创建
*/
tasks.whenTaskAdded {
task ->
task.ext.srcDir = 'src/main/java'
}
/**
* 监听某个task开始执行,结束执行
*/
gradle.taskGraph.addTaskExecutionListener(new TaskExecutionListener() {
@Override
void beforeExecute(Task task) {
}
@Override
void afterExecute(Task task, TaskState state) {
}
})
//其他的监听
this.gradle.addBuildListener(new BuildListener() {
@Override
void buildStarted(Gradle gradle) {
//在构建启动时调用
}
@Override
void settingsEvaluated(Settings settings) {
//在加载和计算构建设置时调用,设置对象已完全配置完成可用来加载构建项目
}
@Override
void projectsLoaded(Gradle gradle) {
//从设置创建构建的项目时调用。这些项目都没有评估
}
@Override
void projectsEvaluated(Gradle gradle) {
//构建的项目评估后调用
}
@Override
void buildFinished(BuildResult result) {
//构建完成时调用
}
})
Gradle 的生命周期分为三个阶段,初始化阶段,配置阶段,执行阶段。
初始化阶段:通过 setting.gradle 来判断项目有哪些项目需要初始化,加载需要被初始化的项目的build.gradle 文件,并为每个项目创建 project 对象。如果你的项目有好几个模块,你可以打开 setting.gradle ,每个模块的名字都在里面,如果删除某个模块的名字,则这个模块不会被构建。
include ':app', ':core', ':detegateManager', ':tabHome', ':tabShop', ':tabDiscover', ':tabMall', ':tabMine', ':ui'
rootProject.name='CarSteward'
配置阶段,执行各个项目下的 build.gradle 脚本处理依赖等。完成 project 的配置,构造 Task 链表(这里的链表指的是存在依赖关系的 task 的集合,不是数据结构链表)
执行阶段
根据 task 链表执行某一个特定的task,这个被 task 所以来的其他task都会被先执行
对于 gradle 来说,每一个模块都是一个 project ,对于他来说不存在什么 Library 等模块。他们都是一个项目,如下:
对于 android 来说 这是一个项目,里面有很多模块,但是 gradle中每个模块也相当于一个 project。我们可以通过一个命令来查看一下:gradlew projects
Root project 'CarSteward'
+--- Project ':app'
+--- Project ':core'
+--- Project ':detegateManager'
+--- Project ':tabDiscover'
+--- Project ':tabHome'
+--- Project ':tabMall'
+--- Project ':tabMine'
+--- Project ':tabShop'
\--- Project ':ui'
可以看到有一个 Root project ,其他的则是子project。从这个结构可以看出来 gradle 是以树的结构来管理所有的 project。但是这个树只有两层,因为我们不可能在 module 中新建一个模块
Project 是脚本的核心,每个 project 的初始化都是通过 build.gradle 文件,所以构建的核心脚本都要编写在 build.gradle 中
每一个模块都必须有一个 build.gradle 文件,否则他就不会被任务是一个 project。
根 Project 的作用就是用来管理所有的子project,他提供了一系列的 api 来进行管理。
子 Project 则是用来对应输出的,一个子 project 对应一个输出,例如上面的 app project就对应着一个 apk 的输出,而 core 等其他的就对应一个 aar 的输出 。如果是 java 的项目,则对应的就是 jar 的输出。
project 相关的api
让当前 project 可以操做他的父 project 以及管理它子 project 的能力
def getProjects() {
println "------------"
//获取所有project 并遍历
this.getAllprojects().eachWithIndex {
Project entry, int i ->
if (i == 0) {
println "Root Project ${entry.name}"
} else {
println "+--- Project ${entry.name}"
}
}
println "------------"
}
this.getProjects()
//结果:
------------
Root Project CarSteward
+--- Project app
+--- Project core
+--- Project detegateManager
+--- Project tabDiscover
+--- Project tabHome
+--- Project tabMall
+--- Project tabMine
+--- Project tabShop
+--- Project ui
------------
//获取所有子 project 并遍历
this.getSubprojects().eachWithIndex {
Project entry, int i ->
println "+--- Project ${entry.name}"
}
//获取父 project,需要在子 project 中执行
def getParentProject() {
println "----" + this.getParent().name
}
//获取 RootProject
println "----" + this.getRootProject().name
注意:不管是project 中的方法也好,代码也好都是在配置阶段执行的。
//获取指定的 project,第一个参数为路径,第二个为闭包
project("core") {
Project project ->
println project.name //获取 name
apply plugin: 'com.android.library' //指定 plugin
group 'com.123' //指定 group
version '1.0.0' //指定 版本号
dependencies {
//指定 依赖
}
android {
//指定 android
}
}
我们可以直接在RootProject 中获取子 Project,并且调用一些方法,如上,可以完全将 core 中的配置移到 RootProject 中也没有任何问题。但是一般都不会这样做。
//配置当前结点工程和所有子 project
allprojects {
version '2.0.0'
group 'com.ww.com'
}
println project('core').group
println project('core').version
//结果:
com.ww.com
2.0.0
//不包括当前结点工程,只包含他的子 project
subprojects {
version '2.0.0'
group 'com.ww.com'
}
使用 allprojects 就可以替换当前及子 project 中的配置。
task 相关 api
为当前的 project 提供了新增 task 以及使用当前 project 中 task 的能力
task 内容有点多,需要单独提出来
属性相关的 api
gradle 本身提供了一些属性,属性 api 让我们在 project 中可以添加额外的属性能力
public interface Project extends Comparable<Project>, ExtensionAware, PluginAware {
/**
* 默认的项目构建文件名,所以我们的自 project 中才必须有 build.gradle
*/
String DEFAULT_BUILD_FILE = "build.gradle";
/**
* 分割符
*/
String PATH_SEPARATOR = ":";
/**
* 每个 project 都有一个build 文件夹,就是下面这个属性,文件夹中则是输出
*/
String DEFAULT_BUILD_DIR_NAME = "build";
/**
* 这个字段是一个文件,这个文件中定义的所有属性都是全局的,在所有的.gradle 文件中
* 以使用,注意只能是 key value 类型
*/
String GRADLE_PROPERTIES = "gradle.properties";
......
}
扩展属性:
在 RootProject 中定义扩展属性,如下:
subprojects {
ext{
compile_sdk_version = 29
min_sdk_version = 15
target_sdk_version = 29
version_code = 1
version_name = APP_VERSION
build_tools_version = "29.0.2"
}
}
通过这种方式就可以子 project 中直接使用这些属性了。只需要定义一次,就可以定义在所有的子 project 中。
但是这种有一个缺陷,虽然看起来我们只定义了一次,但是本质上 gradle 会为每一个project 都定义这些属性,我们只是感觉操作方便了一些而已。
改进一哈:
直接在 RootProject 中定义 ext。而不是定义在 subprojects 中。这样子工程就可以直接通过获取 rootProject来获取这些属性了。
ext{
compile_sdk_version = 29
min_sdk_version = 15
target_sdk_version = 29
version_code = 1
version_name = APP_VERSION
build_tools_version = "29.0.2"
}
子工程的获取:
compileSdkVersion this.rootProject compile_sdk_version
gradle 规定父类中所有的属性都可以被子类继承,所以这里就可以这样写:
compileSdkVersion compile_sdk_version
但是如果将所有的扩展属性都定义在 RootProject 中,感觉会非常臃肿,所以我们可以新建一个 config.gradle 文件,将 扩展属性定义在里面,然后在 RootProject 中引入即可,如下:
//从根工程下寻找 config.gradle 文件
apply from: file('config.gradle')
我们还可以再 gradle.properties 文件中定义属性,但是在这个文件中只能定义 key value 类型的属性,所以他的使用有些限制。使用如下:
android.useAndroidX=true
android.enableR8=false
isDebug=false
# 版本
APP_VERSION=1.0.3
如上面是引入 AndroidX,关闭 R8。下面的 isDebug 是我们自定义的,定义完后我们就可以在任何的 .gradle 文件中使用 isDebug。如下所示:
if (isDebug.toBoolean()){
apply plugin: 'com.android.application'
}else {
apply plugin: 'com.android.library'
}
file 相关的 api
这个 file 主要用于操作当前 project 下文件的处理
println getRootDir().absolutePath //获取根工程路径
println getBuildDir().absolutePath //获取 build 路径
println getProjectDir().absolutePath //获取工程的路径
//结果:
C:\Users\Administrator\Desktop\345\Project\CarSteward
C:\Users\Administrator\Desktop\345\Project\CarSteward\build
C:\Users\Administrator\Desktop\345\Project\CarSteward
上面就是获取路径
//文件定位,以当前的 project 来寻找文件
def getContent(String pach) {
try {
//返回文件内容
return file(pach).text
} catch (GradleException e) {
println "file not found..."
}
}
println getContent("config.gradle")
//结果:
ext{
compile_sdk_version = 29
min_sdk_version = 15
target_sdk_version = 29
version_code = 1
version_name = APP_VERSION
build_tools_version = "29.0.2"
}
可以看到已经找到 config.gradle 并且将他的内容全部打印出来了。file只能定位一个文件,但是 files 可以定位多个。
//copy
//将 app 下的签名文件 copy 到 根工程的 build 目录下
copy {
from(file('CarSteward.jks'))
into getRootProject().getBuildDir()
}
//copy 文件夹
copy {
from(file('build/outputs/'))
into getRootProject().getBuildDir().path + "/outputs/"
}
//copy 文件夹
copy {
from(file('build/outputs/'))
into getRootProject().getBuildDir().path + "/outputs/"
exclude {
//可以配置哪些不需要copy
}
rename {
//可以修改 name
}
}
注意 copy 完后需要刷新一下。。。
//对文件树进行遍历
fileTree('build/') {
FileTree fileTree ->
fileTree.visit {
FileTreeElement element ->
println element.file.name
// copy 内容
copy {
from element.file
into getRootProject().getBuildDir().path + "/"
}
}
}
gradle 生命周期的 api
这个在上面已经说过了
其他 api
例如对 project 添加依赖,添加配置,引入外部文件等等
buildscript
其实最重要的就是 buildscript 方法了,如下:
//buildscript 中就是依赖配置的核心方法
buildscript {
ScriptHandler scriptHandler ->
//配置工程的仓库地址
scriptHandler.repositories {
RepositoryHandler repositories ->
repositories.jcenter()
repositories.mavenCentral()
repositories.mavenLocal()
repositories.ivy {}
repositories.maven {}
}
//配置工程中插件的地址
scriptHandler.dependencies {
}
}
buildscript 方法接收一个闭包参数,查看源码可以知道这个闭包的参数是 ScriptHandle ,
而 ScriptHandle 有一个 repositories 方法,我看看一哈源码:
```java
/**为脚本依赖项配置存储库。对{@link执行给定的闭包
这个处理程序的RepositoryHandler}。{@link RepositoryHandler}作为闭包的闭 包传递给闭包委托。
*/
void repositories(Closure configureClosure);
在这个方法中为脚本依赖配置存储库。具体的实现在闭包中,我们也可以看到他的参数是一个闭包。由注释可以看到闭包的参数为 RepositoryHandler。下面看一哈这个类
public interface RepositoryHandler extends ArtifactRepositoryContainer {
MavenArtifactRepository jcenter();
MavenArtifactRepository mavenCentral(Map<String, ?> args);
MavenArtifactRepository mavenCentral();
MavenArtifactRepository mavenLocal();
MavenArtifactRepository google();
MavenArtifactRepository maven(Closure closure);
}
这里我列举了几个非常常见的,是不是非常熟悉。我们为脚本依赖配置的存储库都是在这里进行引入的,一般使用比较多的就是 jcenter,google,maven 等。注意 maven 还可以传入闭包,意味着他可以进行深入的配置,其实它内部可以配置,地址,name,账号密码等。
最上面 buildscript 中的代码写的是非常容易理解的,我们将参数都列举了出来,并且调用的时候都使用了参数进行调用,其实我们可以完全进行简写,当然,前提是你对 groovy 的闭包非常熟练。如下所示:
buildscript {
ScriptHandler scriptHandler ->
//配置工程的仓库地址
repositories {
RepositoryHandler repositories ->
jcenter()
mavenCentral()
mavenLocal()
ivy {}
maven {}
}
//配置工程中插件的地址
scriptHandler.dependencies {
}
}
可以看到这里直接是调用方法,前面并没有使用 参数.方法(),这是为啥呢?还记得 owner 吗,默认情况下他指的是当前类对象,单是如果闭包嵌套的话他指的就是闭包,然后 delegate 默认和 owner 是一样的。这里如果没有使用参数调用的话默认使用的就是 delegate 了。
其实闭包只有一个参数,也可以不用写的。如下
buildscript {
//配置工程的仓库地址
repositories {
jcenter()
mavenCentral()
mavenLocal()
// ivy {}
// maven {}
}
//配置工程中插件的地址
// scriptHandler.dependencies {
//
// }
}
是不是非常熟悉,这就是 as 自动为我们创建的东西,而刚才我们只是了解了一下他的过程而已,至于这里我注释了几行代码,是因为 ivy 和 mave 参数都是闭包,要运行的话必须传入闭包,所以我给注释掉了。下面的 dependencies 其实也一样。下面来看一下 dependencies
scriptHandler 中还有一个 dependencies 方法。
/ **
*配置脚本的依赖项。针对此处理程序,针对{
@link DependencyHandler}执行给定的关闭。 {
@link DependencyHandler}作为闭包的委托传递到闭包。
*
* @param configureClosure闭包用于配置依赖项。
* /
void dependencies(Closure configureClosure);
可以看到这是用来配置脚本依赖的(注意是脚本依赖,也就是 gradle 用到的插件依赖),传入一个闭包,闭包的参数为 DependencyHandler。
所以这里定义的插件是给 gradle 使用的。并非是应用程序。
dependencies {
classpath 'com.android.tools.build:gradle:3.5.2'
classpath 'com.jakewharton:butterknife-gradle-plugin:10.1.0'
// 美团多渠道打包插件
classpath 'com.meituan.android.walle:plugin:1.1.6'
//bugly
classpath "com.tencent.bugly:tinker-support:1.2.1"
}
如上面这些,都是给 gradle 使用的,关于 classpatch 我在 DependencyHandler 中并没有发现这个方法,但按住 ctrl 点击这个方法又看到他是 DependencyHandler 中的方法,点击去后跳的位置是错误的,不晓得是为啥。。。。
dependencies
应用程序使用的 dependencies ,我们看一下 dependencies 下都能配置什么内容,点击去看一下你就会发现他是 Project 类下的方法:
/ ***
<p>配置此项目的依赖项。
*
* <p>此方法针对此项目的{
@link DependencyHandler}执行给定的关闭。 {
@link
* DependencyHandler}作为闭包的委托传递到闭包。
*
* <h3>示例:</ h3>
*请参见{
@link DependencyHandler}文档
*
* @param configureClosure闭包以用于配置依赖项。
* /
void dependencies(Closure configureClosure);
查看参数是一个闭包,这个闭包可以用于配置依赖项,参数为 DependencyHandler。
使用如下:
dependencies {
implementation project(path: ':core')
implementation project(path: ':detegateManager')
implementation 'com.tencent.bugly:crashreport_upgrade:1.4.2'
implementation 'com.tinkerpatch.sdk:tinkerpatch-android-sdk:1.2.14'
implementation 'com.tencent.bugly:nativecrashreport:3.7.1'
}
在 RootProject 的 gradle 中 dependencies 是为gradle添加插件的,而 子 project 则是给应用程序添加依赖。
如果项目中的依赖太多的话就会有可能导致依赖冲突。如一个第三方库依赖了别的第三方库,而指不定还有些库也依赖了别的第三方库。如果第三方库相同就会导致依赖冲突。有冲突后编译器就会报错。
api('com.joanzapata.iconify:android-iconify-fontawesome:2.2.2') {
exclude group: 'com.android.support'
}
例如上面的 iconify 库,编译器报了依赖冲突,查看后发现是 suport 的冲突,可以使用 exclude 方法来解决排除掉 support 库即可。还有一种方式如下:
exclude module : 'com.android.support'
如果你不想使用第三方库中所依赖的库,可以使用以下关键字禁用
api('com.joanzapata.iconify:android-iconify-fontawesome:2.2.2') {
exclude group: 'com.android.support'
transitive false
}
将 transitive 设置为 false 后当前项目就不会调用到库中所依赖的库了。
赖了别的第三方库,而指不定还有些库也依赖了别的第三方库。如果第三方库相同就会导致依赖冲突。有冲突后编译器就会报错。
api('com.joanzapata.iconify:android-iconify-fontawesome:2.2.2') {
exclude group: 'com.android.support'
}
例如上面的 iconify 库,编译器报了依赖冲突,查看后发现是 suport 的冲突,可以使用 exclude 方法来解决排除掉 support 库即可。还有一种方式如下:
exclude module : 'com.android.support'
如果你不想使用第三方库中所依赖的库,可以使用以下关键字禁用
api('com.joanzapata.iconify:android-iconify-fontawesome:2.2.2') {
exclude group: 'com.android.support'
transitive false
}
将 transitive 设置为 false 后当前项目就不会调用到库中所依赖的库了。
到这里 Gradle 的基础就说的差不多了。已经常用的 api 使用等,关于 task 将会在下一篇中讲解。而且他是非常重要的!!!
文章浏览阅读1.6w次,点赞8次,收藏18次。已解决(selenium操作火狐浏览器报错)TypeError: __init__() got an unexpected keyword argument ‘firefox_options‘_typeerror: __init__() got an unexpected keyword argument 'chrome_options
文章浏览阅读315次。python实现代码# -*- coding: utf-8 -*-import mathdef get_average(records):"""平均值"""return sum(records) / len(records)def get_variance(records):"""方差 反映一个数据集的离散程度"""average = get_average(records)return sum(..._pycharm方差计算代码
文章浏览阅读902次。一、前提:cookie是保存在本地,用来记录用户信息,最典型的作用是判断用户是否已经登录。如果一个接口,需要用户登录后,才能进行操作,如下,修改用户信息那么这时候,就需要用到cookie去识别这个登录的用户,因为要修改的是这个登录的用户的信息。二、使用1、jmeter.properties 中 将CookieManager.save.cookies 设置为true。完成后重启jmet..._jmeter中post请求如何更改每次的用户名
文章浏览阅读7.5k次,点赞2次,收藏2次。虚拟环境的好处:搭建独立的python运行环境,不与其他产生冲突虚拟环境有助于包的管理和防止版本冲突3.删除卸载方便虚拟环境的搭建:1.进入python的Scripts下,执行:pip3 install virtualenv2.选择建立虚拟环境的文件夹,我这边是直接在D盘software下面创建了一个virtualenv,如图:image.png3.创建虚拟环境:virtualenv --no-s..._pycharm没有venv怎么办
文章浏览阅读2.3k次。--pod install时报错,且错误提示中有“ffi”字眼,提示错误:/Library/Ruby/Gems/2.6.0/gems/ffi-1.15.3/lib/ffi/library.rb:275: [BUG] Bus Error at 0x00000001042fc000 ruby 2.6.3p62 (2019-04-16 revision 67580) [universal.arm64e-darwin20]解决方案:juejin.cn/post/698064…--pod repo upd_oc cocospods 安装依赖库之后不能使用模拟器了
文章浏览阅读540次。工欲善其事必先利其器,趁手的工具会使我们开发事半功倍。市面上的编辑器我用过许多,编辑器使用经历Notepad++,(开源)这个应该是最轻量级的吧,查看代码还好,编辑代码就算了官网地址:https://notepad-plus-plus.org/Brackets,(开源)这个也不错,github-star:30k了,上次发布版本是6月..._vscode nextick
文章浏览阅读95次。前言:织梦程序是最知名的cms程序,使用广泛,但很多朋友对织梦还不太熟悉,通过工单分析得知,经常容易出现本文中的问题,本次统一整理出来,希望对新手朋友有帮助,本文写的非常详细,请仔细阅读,一、描述:“dedecms错误警告:连接数据库失败,可能数据库密码不对或数据库服务器出错”如图:分析:用织梦程序制作的站点做迁移服务器后容易出现这个问题,原因是程序中设置的数据库连接信息有误连接不到数据库,解决方..._西部数码支不支持织梦的程序
文章浏览阅读295次。上午在win7下安装MYSQL,只到“net start mysql”这一步报错:3534的错误:于是在百度中搜索关键字“mysql服务无法启动3534”。参考以下两个链接中的方法,解决了3534启动失败的问题:mysql服务无法启动3534错误。http://jingyan.baidu.com/article/219f4bf7e978fcde442d38a9.htmlhttp://blog.cs..._免安装mysql启动失败
文章浏览阅读5.1w次,点赞58次,收藏295次。最近在做项目和复习的时候,用了不少流程图软件给我帮了大忙,所以今天就来分享分享你在网上搜索一下流程图软件,能找到很多很多:但这些软件多数并不是专门绘制流程图的软件,它可能是一些思维导图软件、或者说一些产品交互原型图软件,使用时或多或少有些麻烦。而且,普遍这些软件缺点也很多,比如:只有在线版:ProcessOn(https://www.processon.com)导出功能收费:迅捷流程图软件体积庞大:VISIO就没有一款简单易用、绿色免费的流程图软件吗?阿虚花了不少时间,挨着_好用的流程图软件免费
文章浏览阅读1.4k次。cd /data/install_pkgwget https://github.com/azkaban/azkaban/archive/3.50.0.tar.gztar -zxvf 3.50.0.tar.gzvi /data/install_pkg/azkaban-3.50.0/azkaban-common/src/main/java/azkaban/utils/EmailMessage..._centos6.9 azkaban
文章浏览阅读586次,点赞23次,收藏30次。博主介绍:CSDN特邀作者、985计算机专业毕业、某互联网大厂高级全栈开发程序员、码云/掘金/华为云/阿里云/InfoQ/StackOverflow/github等平台优质作者、专注于Java、小程序、前端、python等技术领域和毕业项目实战,以及程序定制化开发、全栈讲解、就业辅导、面试辅导、简历修改。精彩专栏 推荐订阅2023-2024年最值得选的微信小程序毕业设计选题大全:100个热门选题推荐2023-2024年最值得选的Java毕业设计选题大全:500个热门选题推荐。
文章浏览阅读944次。由于需要用pyqt给yolov8做一个界面,而ultralytics一层嵌一层,不是很好用,所以对它的这个源码进行精简,具体代码我放到了这里,ultralytics使用的版本是8.0.54。具体代码如下,需要根据自己的情况来修改data的配置文件以及权值文件,在代码的49和50行。_from ultralytics.utils.plotting import annotator, colors, save_one_box modul