Gradle高级自定义、多项目构建

Gradle8的init.gradle隐藏玩法:自定义仓库优先级+多源混合配置实战 本文深入解析Gradle8中init.gradle的高级用法,重点介绍如何通过自定义仓库优先级和多源混合配置大幅提升构建效率。实战演示了包括本地缓存优先、阿里云镜像加速、中央仓库兜底等策略,以及企业级仓库权重系统的实现方案,帮助开发者解决依赖下载慢、构建失败率高等痛点问题。 阅读详情

一、高级自定义

1.1、使用共享库

Android的包(比如android.app、android.content、android.view、android.widget等)默认都是包含在Android SDK里面的,所有的应用都可以直接使用它们,系统会帮我们自动链接它们,不会出现找不到相关类的情况。还有一些库,比如com.google.android.maps、android.test.runner等,这些库是独立的,并不会被系统自动链接,所以我们使用它们的话,需要单独的进行生成使用,这些类库我们称为共享库。

在AndroidManifest.xml文件中,指定要使用的库:
<uses-library 
android:name="com.google.android.maps"
android:required="true"/>

这样就声明了需要使用maps这个共享库。声明之后,在安装生成的apk的时候,系统会根据我们的定义,帮助我们检测手机系统是否有我们需要的共享库。因为我们设置了android:required="true",如果手机系统不满足,将不能安装该应用。

在Android中,除了标准的SDK,还存在两种库:

- add-ons附件库,位于add-ons目录下,这些库大部分是第三方厂商或者公司开发的,一般是为了让开发者使用,但是又不愿意暴露具体标准实现的;对于该类库,Android Gradle会自动解析,帮我们添加到classpath里。

- 另一类是optional可选库,位于platforms/android-xx/optional目录下,一般是为了兼容旧版本的api,比如org.apache.http.legacy,这是一个HttpClient库。对于该类库,则不会帮我们添加到classpath里。

如何自己把这个可选库添加到classpath中?Android Gradle提供了useLibrary方法,让我们可以把一个库添加到classpath中。

android{
useLibrary 'org.apache.http.legacy'
}

除了上述配置,最好在AndroidManifest文件中配置一下use-library标签,以防出现问题。通过PackageManager.getSystemSharedLibraryNames()获取共享库的所有名字。

1.2、批量生成Apk的文件名

Android相对于Java工程要复杂的多,Java工程通过project.tasks.xx就可以访问xx任务,但是对Android来说,因为它有很多相同的任务,这些任务的名字都是通过buildTypes和Product Flavors生成的,是动态创建和生成的,而且生成的时间是比较靠后的,如果你还是像原来一样在某个闭包里通过project.tasks获取一个任务,会提示找不到任务,因为还没有生成。

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.example.test.gradletest"
        minSdkVersion 14
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            zipAlignEnabled true
        }
        debug {

        }
    }

    productFlavors {
        google {
            applicationIdSuffix '.google'
            flavorDimensions "default"
        }
        baidu {
            applicationIdSuffix '.baidu'
            flavorDimensions "default"//新增
        }
    }

    //如下方法在gradle升级到3.x之后发生了变化,如下所示
    android.applicationVariants.all { variant ->
        variant.outputs.all { output ->
            if (output.outputFile != null
                    && output.outputFile.name.endsWith('.apk')
                    && 'debug' == variant.buildType.name) {
                def flavorName = variant.flavorName.startsWith("_") ? variant.flavorName.substring(1) : variant.flavorName
                outputFileName = "Example_${flavorName}_v${variant.versionName}_${buildTime()}.apk"
            }
        }
    }
}

def buildTime() {
    def date = new Date()
    def formattedDate = date.format('yyyymmdd')
    return formattedDate
}
--------------------------------------------------------------------------

buildVariants = buildTyps x productFlavors

打包命令:
只打Release包 - 
./gradlew assembleRelease
只打Debug包 - 
./gradlew assembleDebug
只打baidu的渠道包 - 
./gradlew assemblebaidu
只打baidu的release渠道包
./gradlew assemblebaiduRelease

----------------------------------------------------------------------------
variant与variant输出产物列表:
baiduDebug --- variant.name
app-baidu-debug.apk --- output.outputFile.name
baiduRelease --- variant.name
app-baidu-release-unsigned.apk --- output.outputFile.name
googleDebug --- variant.name
app-google-debug.apk --- output.outputFile.name
googleRelease --- variant.name
app-google-release-unsigned.apk --- output.outputFile.name

如上,即可完成批量修改生成的apk文件名的任务。

Android对象为我们提供了3个属性:applicationVariants、libraryVariants、testVariants。对应了Android三种不同类型的项目。通俗的讲,它们都是Android构建的产物。它们基于BuildTypes和ProductFlavors生成的产物。

applicationVariants是一个DomainObjectCollection集合,通过其all方法可以遍历所有的variant。比如googleDebug、googleRelease、baiduDebug、baiduRelease。applicationVariants中的每一个都是ApplicationVariant,它有一个outputs作为它的输出。每一个ApplicationVariant至少有一个输出,也可以有多个,所以这里的outputs属性是一个List集合。

版本名:major.minjor.patch,即主版本号.副版本号.补丁号

1.3、动态配置AndroidManifest文件

通过ProductFlavor的ManifestPlaceHolder属性(是一个Map类型)就可以配置多个占位符。

    productFlavors {
        google {
            applicationIdSuffix '.google'
            flavorDimensions "default"
            manifestPlaceholders.put("UMENG_CHANNEL", "google")
        }
        baidu {
            applicationIdSuffix '.baidu'
            flavorDimensions "default"
            manifestPlaceholders.put("UMENG_CHANNEL", "baidu")
        }
    }
--------------------------------------------
如果有几十个渠道要发布,每个渠道都这么写太多太累,可以通过如下的方式,几行代码解决:
    productFlavors.all { flavor ->
        manifestPlaceholders.put("UMENG_CHANNEL", name)
    }
--------------------------------------------
使用:
<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <meta-data android:value="${UMENG_CHANNEL}" android:name="UMENG_CHANNEL"/>
......
</application>

在构建的时候,会把AndroidManifest文件中的占位符变量替换为对应的value的值。

1.4、自定义BuildConfig

BuildConfig这个类是由Android Gradle构建脚本在编译后生成的,自动生成的,不能修改。默认情况下一般是这样的:

public final class BuildConfig {
  public static final boolean DEBUG = Boolean.parseBoolean("true");
  public static final String APPLICATION_ID = "com.example.test.gradletest";
  public static final String BUILD_TYPE = "debug";
  public static final String FLAVOR = "";
  public static final int VERSION_CODE = 1;
  public static final String VERSION_NAME = "1.0";
}

你会发现这些差不多就是我们当前构建渠道的基本信息了。它们都是常量,相比我们获取这些信息的其他方式,无疑是最方便的。例如获取当前的包名,一般我们都会使用context.getPackageName()函数,这个函数又有很多的实现,很麻烦,很复杂,性能也不高。如果直接引用BuildConfig.APPLICATION_ID就方便多了,性能也非常快。

还有,BuildConfig.DEBUG,在debug模式下它的值是true,在release模式下是false,不用我们每次都去改变这个值,Android Gradle会帮我们自动生成修改,非常方便。通过BuildConfig.DEBUG,很容易区分当前的开发模式,以便控制日志的打印。

如何自定义BuildConfig,新增一些常量呢?

BaseFlavor - 函数原型

public void buildConfigField(
            @NonNull String type, @NonNull String name, @NonNull String value)

使用方式如下:

  productFlavors {
        google {
            applicationIdSuffix '.google'
            flavorDimensions "default"
            manifestPlaceholders.put("UMENG_CHANNEL", "google")
            buildConfigField 'String', 'WEB_URL', '"https://www.google.com"'//注意:别丢了双引号
        }
        baidu {
            applicationIdSuffix '.baidu'
            flavorDimensions "default"
            manifestPlaceholders.put("UMENG_CHANNEL", "baidu")
            buildConfigField 'String', 'WEB_URL', '"https://www.baidu.com"'
        }
    }

这样当我们需要使用的时候,直接使用这个BuildConfig.WEB_URL即可。这种用法不仅可以在productFlavor中,buildType中同样适用。

1.5、动态添加自定义的资源

这里讲的自定义资源是专门针对的res/values类型资源的,它们不光可以在res/values文件夹里使用xml的方式定义,还可以在Android Gradle中定义,这大大增加了构建的灵活性。

BaseFlavor - 函数原型
public void resValue(@NonNull String type, @NonNull String name, @NonNull String value)

实现这一功能的正式resValue方法,它在BuildType和ProductFlavor这两个对象中都存在,也就是说可以针对不同的渠道或者构建类型来自定义特有的资源。和BuildConfig的用法非常类似。

productFlavors {
        google {
            applicationIdSuffix '.google'
            flavorDimensions "default"
            manifestPlaceholders.put("UMENG_CHANNEL", "google")
            buildConfigField 'String', 'WEB_URL', '"https://www.google.com"'
            resValue 'String', 'channel_tips', '"这是google渠道"'
        }
        baidu {
            applicationIdSuffix '.baidu'
            flavorDimensions "default"
            manifestPlaceholders.put("UMENG_CHANNEL", "baidu")
            buildConfigField 'String', 'WEB_URL', '"https://www.baidu.com"'
            resValue 'String', 'channel_tips', '"这是baidu渠道"'
        }
    }

当我们使用resValue方法时,Android Gradle帮我们生成的资源在哪里呢?其实都在我们的工程中。

app\build\generated\res\resValues\baidu\debug\values\generated.xml

generated.xml具体内容:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <!-- Automatically generated file. DO NOT MODIFY -->

    <!-- Values from product flavor: baidu -->
    <item name="channel_tips" type="String">"这是baidu渠道"</item>

</resources>

1.6、Java编译选项

Android对象提供了一个compileOptions方法,接受一个CompileOptions类型的闭包作为参数,来对Java编译选项进行配置。

------BaseExtension----
public void compileOptions(Action<CompileOptions> action)
------CompileOptions---
public class CompileOptions {
    private static final String VERSION_PREFIX = "VERSION_";

    @Nullable
    private JavaVersion sourceCompatibility;//Java 源代码的编译级别

    @Nullable
    private JavaVersion targetCompatibility;//配置生成的Java字节码版本

    @NonNull
    private String encoding = Charsets.UTF_8.name(); //编码

......
}
具体用法:
android {
    .......
    compileOptions {
        encoding 'utf-8'
        targetCompatibility = JavaVersion.VERSION_1_8
        sourceCompatibility = JavaVersion.VERSION_1_8
    }
}

 1.7、adb操作选项配置

在Android Gradle中,预留了对adb的一些选项的控制配置,它就是adbOptions{}闭包。和compileOptions用法类似,查看源码就可以知道哪些可以配置的选项了。

adbOptions的原理是什么呢?

我们知道adb这个命令可以帮助我们连接android手机,对于Android Gradle这个插件,也不例外,比如运行调试的时候,Android Gradle插件的底层还是调用adb命令,Android Gradle只不过在其上做了一层包装。在Android Gradle的脚本中,可以通过adbOptions闭包对adb的选项进行配置,然后实例化手机到Android对象中一个叫AdbOptions类型的变量adbOptions中。最后Android Gradle调用adb命令的时候,把这些配置作为adb命令的参数传递给adb即可。

1.8、其他可配置Option

dexOptions具体用法类似adbOptions,具体可配置项可查看源码。

1.9、65535方法限制 - 为啥是65535?

Java源文件都被打包成了一个DEX文件,这个文件就是优化过的、Dalvik虚拟机可执行的文件,Dalvik虚拟机在执行DEX文件的时候,使用了short这个类型来索引DEX文件中的方法,这意味着单个DEX文件可以被定义的方法最多是65535个,当我们定义的方法数超过这个数量时,就会出现错误的提示信息。

MultiDex:对于Android 5.0之后的版本,使用了ART的运行时方式,可以天然支持App有多个DEX文件。ART在安装App的时候执行预编译,把多个DEX文件合并成一个oat文件执行。5.0之前的版本,则需要使用MultiDex库。

二、多项目构建

Android App项目不光可以引用Android Lib项目,还可以引用Java Lib项目。Android Lib是打包成aar包,Java Lib是打包成jar包。引用Android库项目是引用的一个库项目发布出来的aar包,默认情况下,Android库项目发布出来的包都是Release版本。可以在android{}闭包中通过defaultPublishConfig进行配置。

库项目也可以单独发布到自己的Maven私服,推荐Nexus Repository Manager。然后就可以在依赖配置里引用刚发布的aar包了。

Bugku中的source 进入环境后 我们首先查看源码可以得到一个flag 这肯定是个假的(已经提交过了确实是个假的) 题目提示要用Linux 这里使用的是kali 我们首先dirsearch一下这个网站 可以看到有.git文件泄露 也可以点开那个链接但是在里面没有找到flag 然后选择下载这个.git文件 然后进入这个文件夹 输入git reflog查看文件状态 可以看到有四个都有flag is here 一个一个查看git show 然后在40c6d51中发现了我们需要的fl 阅读详情

相关推荐

黑马Java第二阶段:JavaWeb(笔记)

黑马Java第二阶段:JavaWeb(笔记)

chen的博客 5659

【Android Gradle 插件】Gradle 依赖管理 ② ( build.gradle 中的 dependencies 依赖配置 | DependencyHandler#add 方法介绍 )

一、build.gradle 中的 dependencies 依赖配置、 二、DependencyHandler#add 方法介绍

让 学习 成为一种 习惯 ( 韩曙亮 の 技术博客 ) 3106

LangFuse部署与实践

LangFuse的原理主要是基于可观察性和分析技术来监控和优化低延迟消息(LLM)应用。它提供了一套完整的解决方案,通过收集、处理和分析LLM应用在运行过程中产生的各种数据,来生成实时的、深入的、可操作的见解。通过提供实时的、深入的见解和可视化的跟踪功能,LangFuse使得识别和解决应用性能问题变得更加简单和高效。总的来说,LangFuse的原理是通过综合运用可观察性和分析技术,来提供对LLM应用的全面监控和优化能力。这使得开发者和运维团队能够更加高效地管理和维护他们的应用,从而提升用户体验和业务效益。

pumpkin84514的博客 7945

Spring Boot参考文档(12)开发者工具

原文链接:http://www.itbus.tech/detail.html?id=8725Spring Boot包含一些额外的工具,让我们在开发时可以更愉快一些。项目中可以加入spring-boot-devtools模块,为我们的应用带来一些额外的开发时功能。为了添加这个devtools功能,我们需要先添加依赖:Maven<dependencies> <dependency>

明月阁 1761

深度学习赋能胶囊内镜:AI如何实现胃肠道出血的自动检测与分割

在计算机视觉领域,图像分类与目标检测是处理医学影像分析的核心技术。其原理在于通过卷积神经网络(CNN)自动学习图像中的多层次特征表示,实现对特定目标的识别与定位。这项技术的价值在于能够将医生从海量、重复的阅片工作中解放出来,提升诊断效率与一致性,尤其在处理如胶囊内镜产生的数万张连续图像时优势显著。其应用场景广泛覆盖了医学影像的辅助诊断,例如在消化内科,对胃肠道出血的早期发现与精准定位具有重要临床意义。本文聚焦于利用深度学习模型,如U-Net和EfficientNet,构建一个能够从复杂多变的胶囊内镜图像中,

weixin_42533910的博客 381

ctftools-all-in-one使用说明

OAEP (Optimal Asymmetric Encryption Padding) 是一种用于RSA加密的填充方案,目的是提高RSA加密的安全性。在CTF比赛中,如果模数N的两个因子比较接近,使用"费马分解(N)"可能会更快地得到结果;OAEP 是 RSA 的一种标准填充方式(在 PKCS#1 v2.0+ 中定义),因此这类题目本质上仍是 RSA 题,但。,导致你不能直接用常规的 RSA 解密公式 �=�� mod �m=cdmodN 得到有意义的明文。如果你在 CTF 中遇到 RSA 题,

2501_91682449的博客 1718

Gradle基础:12:Option使用说明

在前面的文章中使用过gradle -v来检查gradle的版本,-v是gradle命令的一个Option,这篇文章介绍一下gradle常用的Option以及使用方法。

知行合一 止于至善 2460

OpenLayers源码解析1 Map.js

Map.js 父类:./PluggableMap/PluggableMap 引用:5个模块 ./renderer/Composite.js ./PluggableMap.js ./obj.js ./control.js(控件) ./interaction.js(交互) 主要功能:核心组件,渲染地图 必要参数: view layers target controls和interactions要是未指定,使用默认值 方法:createRenderer()? /** * @module ol/Map */ i

qq_45005996的博客 1898

Gradle基础---构建+插件编写+插件分析(笔记二)

上一篇文章对gradle基础概念进行了笔记https://blog.youkuaiyun.com/qq_20395245/article/details/105454881,这篇文件将对构建,插件编写和插件分析的基础进行记录。

qq_20395245的博客 651

Vue3 - 解决报错 Uncaught (in promise) DOMException: Failed to execute ‘insertBefore‘ on ‘Node‘: The node

vue3,报错,vue3报错,Uncaught(inpromise)DOMException:Failedtoexecute'insertBefore'on'Node':Thenodebeforewhichthenewnodeistobeinsertedisnotachildofthisnode,如何解决这个错误,动态渲染,v-if,v-show,insertBefore,详细解决方法,vue3未能在“Node”上执行“insertBefore”:要插入

🏆 前端领域优质创作者 1万+

软件集成:Simulink与STM32联合开发

本文首先通过一个简单的Simulink模型生成代码,然后将代码copy到一个STM32工程中去编译软件。最后将软件下载到STM32F407中,通过串口输出Simulink计算的结果。 阅读本文需要有一定的STM32开发调试经验和Simulink代码生成经验。关于Simulink代码生成可以参考博主的专栏《Simulink代码生成》。 文章目录1 问题引入2 集成方案3 建模与编程过程3.1 Simulink模型搭建3.2 代码生成配置3.3 STM32工程搭建3.4 STM32的main.c文件修改3.4.

u013288925的博客 2万+

spring 编译spring5源码 2020-08-22

场景 近日回顾了下自己写的spring相关的博客,感觉深度不够,而且自己理解的部分比较少,所以打算重拾spring,希望能输出些有价值的东西吧。 工作日沉浸在CRUD的海洋中,肯定是没时间,那只好牺牲自己的休息时间了。。 之前编译过好几次,都没遇到什么大问题,这次有点坑,所以以此博客为输出,希望大家能少走弯路,不喜勿喷。 正常流程 笔者环境:jdk1.8 + gradle-6.6 + IntelliJ IDEA2018.3.6 git拉源码 直接clone github 准备一个github账号和一个gi

TBryant的博客 481

基于 Vivado HLS 的 AC97 音频系统设计

介绍一种基于 FPGA 的 AC97 音频系统设计。系统的核心部件采用 Xilinx Atlys 的板载 Spartan6 XCSLX45 芯片,使用的工具为 Xilinx 的高层 次 综 合 技 术 Vivado HLS。首先使用 C /C + + 代码编写的算法描述系统的 FIR 滤波器; 然后按 照 Vivado HLS 编译工具的规范,将程序代码转换为 RTL 模型,快速、直接地生成对 应左右声道的 FIR IP 核和综合结果; 再结合互连的 MicroBlaze 处理器 IP 核,处理 一段立体声

qq_43416206的博客 327

build.gradle标签详解

通过对标签的详细解析,我们可以看到Gradle构建脚本的强大和灵活。

大乐乐 1850

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Gradle Java 构建入门

随着项目的发展,你可能需要添加更多自定义任务、修改依赖、配置测试等。所有这些都可以通过修改文件来实现。

qq_33240556的博客 616

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Gradle 生态系统:工具与插件的最佳搭档

Gradle 是一个基于 Groovy 语言的开源构建工具,它设计用于构建、测试和发布软件项目,尤其是在 Java 生态系统中得到了广泛应用。Gradle 结合了 Apache Ant 和 Maven 的优点,并提供了一个灵活的 DSL(领域特定语言)来定义项目构建逻辑,同时支持增量构建和依赖管理。

2403_86762465的博客 612

Gradle学习

Gradle是一种构建工具,它抛弃了基于XML的构建脚本,取而代之的是采用一种基于Groovy的内部领域特定语言。近期,Gradle获得了极大的关注,这也是我决定去研究Gradle的原因。 这篇文章是Gradle教程的第一篇,我们有两个目标: 1. 帮助我们学会安装Gradle。 2. 介绍一些基本概念,这有助于我们进一步理解本教程的后面章节。 我们开始吧,先看一下如何安装Grad...

weixin_34292287的博客 188

Gradle Wrapper 深度解析:如何高效管理项目构建环境(附实战案例)

本文深度解析Gradle Wrapper的核心机制与工作流程,阐述其如何通过声明式配置统一管理项目构建环境,确保团队协作与CI/CD中的环境一致性。文章结合实战案例,详细介绍了从Wrapper初始化、分发执行到在多项目及持续集成场景中的高效配置与优化策略,帮助开发者彻底掌握这一构建环境管理利器。

stem5的博客 199

Gradle学习总结

Gradle学习系列 (1). Gradle快速入门 (2). 创建Task的多种方法 (3). 读懂Gradle语法 (4). 增量式构建 (5). 自定义Property (6). 使用java Plugin (7). 依赖管理 (8). 构建多个Project (9). 自定义Task类型 (10). 自定义Plugin 声明:该系列内容均来自网络或电子书籍,...

weixin_30872867的博客 85

【Gradle多项目系列0】多项目结构标准路径构建测试

【Gradle多项目基础1】多项目结构标准路径构建测试

wang2leee的博客 1737

gradle复合构建多项目构建

文章目录什么是复合构建复合构建适用的场景:如何声明复合构建方式1:通过gradle命令行的--include-build选项实现复合构建方式2:在setting.gradle文件中使用includeBuild语句声明复合构建方式2-补充:不修改my-app/setting.gradle文件实现复合构建注意:一个构建需要满足什么条件才能被复合构建引入? 什么是复合构建 简单地说,Gradle的复合构建就是一个构建包含了其它构建。 Gradle的复合构建跟多项目构建很相似, 唯一的区别是多项目构建引入的是单个p

天空之蓝的博客 2216

Gradle之多项目与混合构建

Multi-project builds 随着大型的单项目构建发展所面临的各种挑战,多项目构建应运而生。 多项目构建的结构如下:包括一个root顶层项目(包括build和setting脚本),之下再包含一个或多个子项目(包含build脚本):root-project ├── build.gradle ├── gradle │ └── wrapper │ ├── gradle-wrap

Android 3424

【gradle】MAC下用gradle构建部署springboot项目

MAC下用gradle构建部署springboot项目

YiQieFuCong的博客 1万+

Gradle基础学习(四) 认识多项目构建

认识多项目构建,了解常规构建和复合构建。

Roy1986613的博客 2130

【Gradle 多模块系列1】 多项目构建子项目创建

Gradle通过多项目构建和子模块创建实战用例

wang2leee的博客 2241

Gradle父子项目构建

Gradle对构建模块化项目提供了强大的支持,在Gradle中每一个模块都是一个项目,称之为Gradle多项目构建技术,多项目构建实现了项目模块化,降低代码耦合度,增加内聚性,本篇文章将简单介绍如何使用Gradle进行多项目构建。 1、组装多项目构建: Gradle整个项目是由一个根目录和多个模块的子目录构成,在根目录下新建build.gradle构建脚本,使用gradle projec...

HELLOW,文浩 5001

高级架构三 Gradle基础到高级

Gradle配置tomcat

东风麦芽糖 1657
上一篇: Gradle插件相关、属性配置
下一篇: 组件化开发基础
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值