Gradle筑基——Gradle Maven仓库管理
基础概念:
1.POM
pom:全名Project Object Model
项目对象模型,用来描述当前maven
项目发布模块的基础信息
pom主要节点信息如下:
配置 | 描述 | 举例('com.android.tools.build:gradle:4.1.1') |
---|---|---|
groupId | 组织 / 公司的名称 | com.android.tools.build |
artifactId | 组件的名称 | gradle |
version | 组件的版本 | 4.1.1 |
packaging | 打包的格式 | aar |
2.仓库
我们在开发中经常使用到第二/三方插件或者第二/三方库,就是存储在仓库中的
2.1:仓库种类:
- 本地仓库:存储在本地设备中的仓库以及远程仓库中下载保存的仓库,统称为本地仓库
- 私有仓库:公司内部仓库,比如是有maven私服搭建的局域网仓库
- 中央仓库:开源社区仓库,我们平时使用的第三方插件或者类库一般都存储在中央仓库,比如
Maven Central
,阿里的国内镜像库等
2.2:仓库构建顺序:
- 1.在本地仓库中查找对应的类库,没有找到
执行2
- 2.按照
repositories
中声明的仓库顺序,在私有仓库和中央仓库查找对应的类库,找到则将类库版本信息下载到本地仓库,没找到则执行3
- 3.前面都没找到对应的类库或者类库版本,则抛出异常‘
没找到对应的类库
’
2.3:仓库声明方式:
项目build.gradle
buildscript {repositories {[Gradle 插件的仓库] }
}
allprojects {repositories {[项目中所有模块依赖的仓库] }
}
模块内build.gradle
repositories{[当前模块依赖的仓库]
}
gradle支持的仓库类型
:
repositories{maven { url '...' }ivy { url '...' }flatDir { dirs '...' }
}
常用的中央仓库:
google() // https://dl.google.com/dl/android/maven2/
mavenCentral() // https://repo.maven.apache.org/maven2/
jCenter()
网络不好的情况下,访问上面的中央仓库会有点慢:可以开考虑使用国内镜像代理
maven { url 'http://maven.aliyun.com/nexus/content/repositories/google' }
maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
maven { url 'http://maven.aliyun.com/nexus/content/repositories/jcenter'}
3.有了Release
版本为啥还需要SNAPSHOT
?
区别
:
- 1.Release版本每次升级都需要更新版本,而SNAPSHOT不需要更新版本,使用原版本即可
- 2.Release版本如果版本没有更新不需要每次都去下载,除非本地仓库被清除,而SNAPSHOT版本每次编译都需要去中央仓库更新版本信息
- 3.常规Release版本是发布上线的版本,SNAPSHOT是测试版本。
- 4.版本名:Release版本:1.0.0,SNAPSHOT版本:1.0.0-SNAPSHOT
使用场景
:
A和B共同开发,如果A修改了代码, 使用常规Release版本则需要每次都发布一个新版本,如果不小心忘记增加版本,B则无法收到更新后的版本, 造成代码不同步,后期会出现不可预料的bug。 使用SNAPSHOT只要A发布了版本,B在每次编译时就可以立即收到A的类库更新信息,可以实时同步代码。
SNAPSHOT以牺牲编译时间换取代码之间的立即可见度
,缺点就是在网络较差的情况下代码编译时间可能常常比较慢。
如何发布组件:
1.发布到本地仓库:
模块级:build.gradle
plugins {id 'groovy' // Groovy Language
// id 'org.jetbrains.kotlin.jvm' // Kotlinid 'java-gradle-plugin' // Java Gradle Pluginid 'maven'
}
...
uploadArchives {repositories {mavenDeployer {repository(url:uri('D:/maven_local'))pom.groupId = 'com.yuhb.upload'pom.artifactId = 'upload'pom.version = '1.0.1'}}
}
同步模块后:点击Gradle面板中对应模块下Tasks:upload
里面的uploadArchives
任务
如果执行成功:则会在对应的本地目录下找到类库信息:
2.搭建maven私服创建私有仓库:
简介
maven
私服其实就是在部门·局域网·中设置一个maven
仓库,所有在局域网中的开发人员都可以使用该仓库:
PS:私服中可以添加自己本地的仓库,也可以代理中央仓库
中的包。毕竟对于一些网络比较差的环境,去中央仓库里面获取数据是一个很耗时的操作
优点
1.节省自己的外部带宽:
2.加速构建过程
3.可以部署第三方构件
4.提高稳定性,增强控制
5.降低中央仓库的负荷
如何搭建Maven私服
1.去官网下载
maven私服启动器 nexus
:
地址:www.sonatype.com/
2.下载后,配置环境变量
后:
在命令行输入:nexus /run
3.nexus启动成功后:在浏览器中输入:
http://localhost:8081/
- 启动界面如下:
点击右上角的sign in
按钮:
输入用户名和密码
:
用户名和密码系统会提示在哪个目录下
4.登录成功后:
- 点击导航栏的设置按钮-->repository进入仓库列表
- 点击
create Repository
创建一个新的本地局域网仓库:
因为我们是为Android项目创建的maven仓库选择maven2:
这里有三个maven2类型仓库:
*hosted*
:本地局域网私服,像官方仓库一样,提供本地私库功能
*proxy*
:提供代理其他仓库的功能,表示这个repository可以代理远程仓库,比如jcenter
google
等远程中央仓库
*group*
:组合多个仓库为一个地址使用
这里我们选择
hosted
仓库即可,大家可以根据自己需求选取
1.输入仓库名称
2.设置maven类型:
*release*
:表示是一个该仓库存储的是一个release版本的第三方库
*snapshot*
:表示存储的是一个不稳定第三方库,需要进程去私服或者中央仓库拉数据:
<repositorys><repository><id>****</id><url>***</url><snapshots><enabled>true</enabled><updatePolicy>(always/ daliy/ interval/ never)</updatePolicy></snapshot></repository>
</repository>
updatePolicy
:表示更新的频率:
always
:每次都需要拉去 daliy
:表示每天需要拉取 interval
:按分钟拉取 nerver
:和release版本一样,不需要重复拉取
点击确定后就创建的一个maven私服:
点击该仓库就可以看到对应的url,这个url就是我们私服的地址。需要在项目中引用:
经过上面的步骤后,我们就搭建好了一个maven
私服,局域网内
用户都可以拉取使用
实战中maven私服接入:
第三方lib库的上传操作
使用as创建一个新的项目,在新建项目下创建一个lib库,命名为:lib_vedio:并在lib_vedio
的build.gradle
工程文件下面,引入maven
库:
实现uploadArchives
的task方法:这个方法用于上传lib库:
plugins {id 'com.android.library'id 'maven'
}//上传的类库名称
def _artifactId = this.getName()
//类库版本
def pomVersionName = '1.0.1'
def pomName = this.getName()
//类库描述
def pomDescription = 'the vedio library for all project'uploadArchives {repositories {mavenDeployer {repository(url:NEXUS_REPOSITORY_URL) {authentication(userName: NEXUS_USERNAME, password: NEXUS_PASSWORD)}pom.project {name pomNameversion pomVersionNamedescription pomDescriptionartifactId _artifactIdgroupId POM_GROUPIDpackaging POM_PACKAGING}}}
}
里面一些变量是在gradle.properties中设置的全局变量:
NEXUS_REPOSITORY_URL=http://localhost:8081/repository/anna_release/
POM_GROUPID=com.anna.android
POM_PACKAGING=aar
NEXUS_USERNAME=admin
NEXUS_PASSWORD=admin123456
设置好后,执行uploadArchives
任务,这个时候我们本地的lib_vedio
库就会上传到我们之前搭建的maven
私服上:
这里因为我们上传了两个版本1.0.0和1.0.1
切记:
如果当前仓库选择的是release属性:则每次上传的版本不能一致,需要在原版本基础上增加
如果选择的是snapshot属性:则可以在不增加版本号的前提下,修改同一版本的代码并上传。
maven私服仓库的接入:
我们在项目的build.gradle
文件中引入maven库:
buildscript {repositories {google()jcenter()maven {url = 'http://localhost:8081/repository/anna_release/'credentials {username = 'admin'password = 'admin123456'}}}dependencies {classpath "com.android.tools.build:gradle:4.1.1"// NOTE: Do not place your application dependencies here; they belong// in the individual module build.gradle files}
}allprojects {repositories {google()jcenter()maven {url = 'http://localhost:8081/repository/anna_release/'credentials {username = 'admin'password = 'admin123456'}}}
}
并在app模块引入lib库文件:
implementation 'com.anna.android:lib_video:1.0.1'
这样就可以在我们项目中愉快使用类库啦。
3.如何发布到Github仓库
如果我们需要开源我们的代码就需要将仓库发布到公共仓库中:
步骤1:在项目级build.gradle
中设置
buildscript {repositories {maven { url 'https://jitpack.io' }}dependencies {classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'}
}allprojects {repositories {maven { url 'https://jitpack.io' }}
}
步骤2:在模块级build.gradle
设置如下
apply plugin: 'com.github.dcendents.android-maven'
group = 'com.github.xxx' // xxx为github 的用户名
步骤3:将源码push
到github
上
步骤4:在github上创建 Release Tag
步骤5:打开jitpack.io 网址, 点击look up
然后会显示出对应的编译版本信息:
红色代表编译失败
蓝色代表编译成功
可通过日志查看编译错误原因:
步骤6:类库引入:在项目级 build.gradle
声明远程仓库,在模块级 build.gradle
中依赖类库。
项目级build.gradle
buildscript {repositories {
...maven { url 'https://jitpack.io' }}dependencies {...classpath 'com.github.ByteYuhb.a_gradle_plugin_sample:uploadversion:1.0.3'}
}
这里我们上传的是一个gradle插件库,所以需要在buildscript中的dependencies声明插件版本信息。
模块级build.gradle
apply plugin: 'com.yuhb.upload'versionInfo {versionName = '1.0.0'versionCode = 1versionUpdateInfo = '当前是第一个版本:初始apk'
}
引入插件的group和扩展信息
结果
: 在编译期:打印出了Gradle插件中的信息:
Task :app:uploadTask
name:1.0.0 code:1 info:当前是第一个版本:初始apk
4.指定发布二进制文件:
使用新版 Maven 插件
,可以直接以指定二进制文件的方式发布组件。例如:
apply plugin: 'maven-publish'publishing {publications {[任务名](MavenPublication) {groupId MAVEN_GROUP_IDartifactId MAVEN_ARTIFACTIDversion MAVEN_VERSIONartifact([文件路径])}}repositories {maven {// 发布仓库路径url MAVEN_RELEASE_URL}}
}
如何封装一个通用发布版本
步骤1:在项目根目录下创建:
maven_publish.gradle
apply plugin: 'maven'uploadArchives {repositories {mavenDeployer {// 是否快照版本def isSnapShot = Boolean.valueOf(MAVEN_IS_SNAPSHOT)def versionName = MAVEN_VERSIONif (isSnapShot) {versionName += "-SNAPSHOT"}// 组件信息pom.groupId = MAVEN_GROUP_IDpom.artifactId = MAVEN_ARTIFACTIDpom.version = versionName// 快照仓库路径snapshotRepository(url: uri(MAVEN_SNAPSHOT_URL)) {authentication(userName: MAVEN_USERNAME, password: MAVEN_USERNAME)}// 发布仓库路径repository(url: uri(MAVEN_RELEASE_URL)) {authentication(userName: MAVEN_USERNAME, password: MAVEN_USERNAME)}println("###################################"+ "\nuploadArchives = " + pom.groupId + ":" + pom.artifactId + ":" + pom.version + "." + pom.packaging+ "\nrepository =" + (isSnapshot ? MAVEN_SNAPSHOT_URL : MAVEN_RELEASE_URL)+ "\n###################################")}}
}
这段脚本会读取
MAVEN_IS_SNAPSHOT
配置参数,如果为 true,会在版本号后追加-SNAPSHOT
后缀,表示快照版本。随后声明了两个仓库:repository(...) 声明的是 Release 仓库地址,而 snapshotRepository(...) 声明的是快照仓库地址。Maven 会自动将版本号带 -SNAPSHOT 后缀的组件发布到 snapshotRepository(...) 仓库中,这样就 自动将正式版本和快照版本分发的不同仓库中。
步骤2:声明项目级
gradle.properties配置参数:
MAVEN_SNAPSHOT_URL = /Users/yuhb/workspace/public/DemoHall/snapshotRepository
MAVEN_RELEASE_URL = /Users/yuhb/workspace/public/DemoHall/releaseRepository
MAVEN_USERNAME =
MAVEN_PASSWORD =
MAVEN_IS_SNAPSHOT = true
MAVEN_GROUP_ID = com.yuhb.demo
参数描述 | |
---|---|
MAVEN_SNAPSHOT_URL | 快照仓库地址 |
MAVEN_RELEASE_UR | 发布仓库地址 |
MAVEN_USERNAME | 仓库账号 |
MAVEN_PASSWORD | 仓库密码 |
MAVEN_IS_SNAPSHOT | 是否快照版本 |
MAVEN_GROUP_ID | 组织 / 公司的名称 |
MAVEN_ARTIFACTID | 组件的名称(在发布模块配置) |
MAVEN_VERSION | 组件的版本(在发布模块配置) |
步骤 3:在发布模块应用脚本
apply from: '../maven.gradle'
...
步骤 4:在发布模块配置参数 (模块级配置参数会覆盖项目级配置参数)
模块级 gradle.properties
MAVEN_ARTIFACTID = maven
MAVEN_VERSION = v1.0.0
MAVEN_IS_SNAPSHOT = true
...
然后在Gradle面板中找到对应模块下的任务uploadArchives,执行成功后就可以将组建发布对应的maven私服上了
本地aar文件引入:
模块级build.gradle
dependencies {...api(name: 'lib-debug', ext: 'aar')
}repositories {flatDir {dirs "libs"}
}
这种方式如果其他模块需要使用就不方便:
方法1
:
在项目级build.gradle
allprojects {repositories {google()mavenCentral()flatDir { dirs project(':aarlib').file('libs') } // 文件夹要放在某个 module 内}
}
这种方式可以在本工程中使用,如果跨工程或者跨设备就不好使了
方法2
:二次打包aar发布到maven仓库
apply plugin: 'maven-publish'def libPath = project.getProjectDir().getAbsolutePath()publishing {publications {lib1(MavenPublication) {groupId MAVEN_GROUP_IDartifactId "lib"version "v1.0.0"artifact(libPath + "/libs/lib.aar")}lib2(MavenPublication) {groupId MAVEN_GROUP_IDartifactId "lib2"version "v1.0.0"artifact(libPath + "/libs/lib2.aar")}}repositories {maven {// 发布仓库路径url MAVEN_RELEASE_URL// 本地仓库地址不适用账号密码// > Failed to publish publication 'maven' to repository 'maven'// > Authentication scheme 'all'(Authentication) is not supported by protocol 'file'// credentials(PasswordCredentials) {// username = MAVEN_USERNAME// password = MAVEN_PASSWORD// }}}
}
相关文章:

Gradle筑基——Gradle Maven仓库管理
基础概念: 1.POM pom:全名Project Object Model 项目对象模型,用来描述当前maven项目发布模块的基础信息 pom主要节点信息如下: 配置描述举例(com.android.tools.build:gradle:4.1.1)groupId组织 / 公司的名称com.…...
c++11:智能指针的种类以及使用场景
指针管理困境 内存释放,指针没有置空;内存泄漏;资源重复释放 怎样解决? RAII 智能指针种类 shared_ptr 实现原理:多个指针指向同一资源,引用计数清零,再调用析构函数释放内存。 使用场景…...

RabbitMQ-默认读、写方式介绍
1、RabbitMQ简介 rabbitmq是一个开源的消息中间件,主要有以下用途,分别是: 应用解耦:通过使用RabbitMQ,不同的应用程序之间可以通过消息进行通信,从而降低应用程序之间的直接依赖性,提高系统的…...

阿里云百炼大模型使用
阿里云百炼大模型使用 由于阿里云百炼大模型有个新用户福利,有免费的4000000 tokens,我开通了相应的服务试试水。 使用 这里使用Android开发了一个简单的demo。 安装SDK implementation group: com.alibaba, name: dashscope-sdk-java, version: 2.…...
亲测有效,通过接口实现完美身份证号有效性验证+身份证与姓名匹配查询身份实名认证接口(实时)
最近发现一个限时认证的接口分享给大家,有需要的拿去试下吧. 附上部分密钥f478186edba9854f205a130aa888733d227a8f82f98d84b9【剩余约125450次,无时间限制】 b6131281611f6e1fc86c8662f549bdd683a68517203ba312【剩余约1300次,无时段限制】 …...

试题11 输出什么?
...

对vue3/core源码ref.ts文件API的认识过程
对toRef()API的认识的过程: 最开始认识toRef()是从vue3源码中的ref.ts看见的,右侧GPT已经举了例子 然后根据例子,在控制台输出ref对象是什么样子的: 这就是ref对象了,我们根据对象中有没有__v_isRef来判断是不是一个ref对象,当对象存在且__v_isRef true的时候他就判定为是一个…...
AWS迁移与传输之AWS DMS
AWS Database Migration Service(AWS DMS)是一项托管的服务,用于帮助企业将现有的数据库迁移到AWS云中的各种数据库引擎中,或者在不同数据库引擎之间进行数据迁移和同步。直接在线迁移,将数据复制到云端,不…...

【ML Olympiad】预测地震破坏——根据建筑物位置和施工情况预测地震对建筑物造成的破坏程度
文章目录 Overview 概述Goal 目标Evaluation 评估标准 Dataset Description 数据集说明Dataset Source 数据集来源Dataset Fields 数据集字段 Data Analysis and Visualization 数据分析与可视化Correlation 相关性Hierarchial Clustering 分层聚类Adversarial Validation 对抗…...
kafka监控配置和告警配置
Kafka的监控配置和告警配置是确保Kafka集群稳定运行的关键部分。以下是一些关于Kafka监控配置和告警配置的建议: 一、Kafka监控配置 集群级别参数监控: log.retention.hours:用于控制消息在日志中保留的时间。监控此参数的值,确…...

关于智慧校园安全用电监测系统的设计
人生人身安全是大家关注的话题,2019年12月中国消防统计近五年发生在全国学生宿舍的火灾2314起(中国消防2019.12.应急管理部消防救援局官方微博),违规电器是引发火灾的主因。如果在各寝室安装智能用电监测器实时监督线路参数&#…...
Flutter 中的 FormField 小部件:全面指南
Flutter 中的 FormField 小部件:全面指南 在Flutter的世界里,表单是用户输入数据的基本方式之一。FormField是一个强大的小部件,它将表单字段的创建、验证和管理集成到了一个易于使用的抽象中。本文将为您提供一个全面的指南,帮助…...

数据库DCL语句
数据库DCL语句 介绍: DCL英文全称是Data Control Language(数据控制语言),用来管理数据库用户、控制数据库的访 问权限。 管理用户: 查询用户: select * from mysql.user;创建用户: create user 用户名主机名 identified by 密码;修改用…...
mysql-日志管理-error.log
日志管理 默认的数据库日志 vim /etc/my.cnf //错误日志 log-error/usr/local/mysql/mysql.log查看数据库日志 tail -f /usr/local/mysql/mysql.log1 错误日志 :启动,停止,关闭失败报错。rpm安装日志位置 /var/log/mysqld.log #默认开启 2 …...

弱密码系统登录之后强制修改密码
在你登录的时候,获取到弱密码,然后将他存到vuex里面,在登录进去之后,index页面再去取,思路是这样的 一、vuex里面定义密码字段 我是直接在user.js里面写的 import { login, logout, getInfo } from /api/login impo…...
解释Python中的多线程和多进程编程
在Python中,多线程(Multithreading)和多进程(Multiprocessing)是两种常见的并发编程技术,用于同时执行多个任务。然而,由于Python的全局解释器锁(GIL,Global Interpreter…...

【LeetCode】【1】两数之和(1141字)
文章目录 [toc]题目描述样例输入输出与解释样例1样例2样例3 提示进阶Python实现哈希表 个人主页:丷从心 系列专栏:LeetCode 刷题指南:LeetCode刷题指南 题目描述 给定一个整数数组nums和一个整数目标值target,请在该数组中找出…...

【论文速读】|探索ChatGPT在软件安全应用中的局限性
本次分享论文:Exploring the Limits of ChatGPT in Software Security Applications 基本信息 原文作者:Fangzhou Wu, Qingzhao Zhang, Ati Priya Bajaj, Tiffany Bao, Ning Zhang, Ruoyu "Fish" Wang, Chaowei Xiao 作者单位:威…...

部门来了个测试开发,听说是00后,上来一顿操作给我看蒙了...
公司新来了个同事,听说大学是学的广告专业,因为喜欢IT行业就找了个培训班,后来在一家小公司实习半年,现在跳槽来我们公司。来了之后把现有项目的性能优化了一遍,服务器缩减一半,性能反而提升4倍!…...

小程序-修改用户头像
1、调用拍照 / 选择图片 // 修改头像 const onAvatarChange () > { // 调用拍照 / 选择图片 uni.chooseMedia({ // 文件个数 count: 1, // 文件类型 mediaType: [image], success: (res) > { console.log(res) // 本地临时文件路径 (本地路径) const { tempFilePath } …...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践
作者:吴岐诗,杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言:融合数据湖与数仓的创新之路 在数字金融时代,数据已成为金融机构的核心竞争力。杭银消费金…...

STM32---外部32.768K晶振(LSE)无法起振问题
晶振是否起振主要就检查两个1、晶振与MCU是否兼容;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容(CL)与匹配电容(CL1、CL2)的关系 2. 如何选择 CL1 和 CL…...

MyBatis中关于缓存的理解
MyBatis缓存 MyBatis系统当中默认定义两级缓存:一级缓存、二级缓存 默认情况下,只有一级缓存开启(sqlSession级别的缓存)二级缓存需要手动开启配置,需要局域namespace级别的缓存 一级缓存(本地缓存&#…...

ubuntu22.04有线网络无法连接,图标也没了
今天突然无法有线网络无法连接任何设备,并且图标都没了 错误案例 往上一顿搜索,试了很多博客都不行,比如 Ubuntu22.04右上角网络图标消失 最后解决的办法 下载网卡驱动,重新安装 操作步骤 查看自己网卡的型号 lspci | gre…...
DAY 26 函数专题1
函数定义与参数知识点回顾:1. 函数的定义2. 变量作用域:局部变量和全局变量3. 函数的参数类型:位置参数、默认参数、不定参数4. 传递参数的手段:关键词参数5 题目1:计算圆的面积 任务: 编写一…...
Monorepo架构: Nx Cloud 扩展能力与缓存加速
借助 Nx Cloud 实现项目协同与加速构建 1 ) 缓存工作原理分析 在了解了本地缓存和远程缓存之后,我们来探究缓存是如何工作的。以计算文件的哈希串为例,若后续运行任务时文件哈希串未变,系统会直接使用对应的输出和制品文件。 2 …...