当前位置: 首页 > news >正文

【Compose multiplatform教程20】在应用程序中使用多平台资源

为项目设置资源后,生成项目以生成提供资源访问权限的特殊类。要重新生成类和所有资源访问器,请再次生成项目或在 IDE 中重新导入项目。ResRes

之后,您可以使用生成的类从您的代码或外部库访问配置的多平台资源。

自定义访问器类生成

您可以使用 Gradle 设置自定义生成的类以满足您的需求。Res

在文件的块中,您可以指定多个设置,这些设置会影响为项目生成类的方式。示例配置如下所示:compose.resources {}build.gradle.ktsRes

compose.resources {publicResClass = falsepackageOfResClass = "me.sample.library.resources"generateResClass = auto
}
  • publicResClass设置为 将生成的类设为公共。默认情况下,生成的类是 internal。trueRes

  • packageOfResClass允许您将生成的类分配给特定的包(以便在代码中访问,以及在最终工件中进行隔离)。默认情况下,Compose Multiplatform 会将软件包分配给类。Res{group name}.{module name}.generated.resources

  • generateResClass设置为 使项目无条件生成类。当资源库仅可传递时,这可能很有用。默认情况下,仅当当前项目对资源库具有显式或依赖项时,Compose Multiplatform 才会使用该值来生成类。alwaysResautoResimplementationapi

资源使用情况

图像

您可以以简单图片、栅格化图片或 XML 矢量的形式访问可绘制资源。除 Android 之外的所有平台都支持 SVG 图像。

  • 如需以图片形式访问可绘制对象资源,请使用以下函数:PainterpainterResource()

@Composable
fun painterResource(resource: DrawableResource): Painter {...}

该函数采用资源路径并返回一个值。该函数在除 Web 之外的所有目标上同步工作。对于 Web 目标,它会为第一次合成返回一个空值,该合成将在后续合成中替换为加载的图像。painterResource()  PainterPainter

  • painterResource()加载 a 用于栅格化图像格式,例如 、 、 、 或 用于 Android XML 矢量可绘制对象格式的 a。BitmapPainter.png.jpg.bmp.webpVectorPainter

  • XML 矢量可绘制对象的格式与 Android 相同,只是它们不支持对 Android 资源的外部引用。

需以Bitmap图像的形式访问可绘制资源,请使用以下函数:ImageBitmap imageResource() 

@Composable
fun imageResource(resource: DrawableResource): ImageBitmap {...}

如需以 XML 矢量的形式访问可绘制资源,请使用以下函数:ImageVector vectorResource()

@Composable
fun vectorResource(resource: DrawableResource): ImageVector {...}

 以下示例说明了如何在 Compose Multiplatform 代码中访问图像:

Image(painter = painterResource(Res.drawable.my_icon),contentDescription = null
)

 

字符串

将所有字符串资源存储在目录中的 XML 文件中。将为每个文件中的每个项生成一个静态访问器。composeResources/values

简单字符串

要存储简单字符串,请在 XML 中添加一个元素:<string>

<resources><string name="app_name">My awesome app</string><string name="title">Some title</string>
</resources>

 要将字符串资源作为 获取,请使用以下代码:String

From 可组合代码

@Composable
fun stringResource(resource: StringResource): String {...}@Composable
fun stringResource(resource: StringResource, vararg formatArgs: Any): String {...}

从不可组合代码

suspend fun getString(resource: StringResource): Stringsuspend fun getString(resource: StringResource, vararg formatArgs: Any): String

例如:

coroutineScope.launch {val appName = getString(Res.string.app_name)
}

您可以在字符串资源中使用特殊符号:

  • \n— 换行

  • \t— 对于 Tab 符号

  • \uXXXX— 对于特定的 Unicode 字符

  • 字符串模板

    目前,参数在字符串资源中具有基本支持:

<resources><string name="str_template">Hello, %1$s! You have %2$d new messages.</string>
</resources>

使用带有可组合代码中的参数的字符串模板时,和 没有区别,例如:%...s%...d

Text(stringResource(Res.string.str_template, "User_name", 100))
字符串数组

您可以将相关字符串分组到一个数组中,并自动将它们作为对象访问:List<String>

<resources><string name="app_name">My awesome app</string><string name="title">Some title</string><string-array name="str_arr"><item>item \u2605</item><item>item \u2318</item><item>item \u00BD</item></string-array>
</resources>

要获取相应的List,请使用以下代码:

From 可组合代码

@Composable
fun stringArrayResource(resource: StringArrayResource): List<String> {...}

从不可组合代码

suspend fun getStringArray(resource: StringArrayResource): List<String>

例如:

coroutineScope.launch {val appName = getStringArray(Res.array.str_arr)
}
复数

当您的 UI 显示某物的数量时,您可能希望支持同一事物的不同数量(一本书、多本书等)的语法一致性,而无需创建以编程方式无关的字符串。

Compose Multiplatform 中的概念和基本实现与 Android 上的数量字符串相同。有关在项目中使用复数的最佳实践和细微差别的更多信息,请参阅 Android 文档。

  • 支持的变体包括 、 、 、 、 和 。请注意,并非所有语言都会考虑所有变体:例如,对于英语,它会被忽略,因为它与除 1 之外的任何其他复数相同。依靠语言专家来了解该语言实际上坚持的区别。zeroonetwofewmanyotherzero

  • 通常可以通过使用数量中立的公式(如 “Books: 1”)来避免数量字符串。如果这不会恶化用户体验,

要定义复数形式,请将元素添加到目录中的任何文件。集合是使用 name 属性(而不是 XML 文件的名称)引用的简单资源。因此,您可以在一个元素下的一个 XML 文件中将资源与其他简单资源组合在一起:<plurals>.xml composeResources/value splural splurals<resources>

<resources><string name="app_name">My awesome app</string><string name="title">Some title</string><plurals name="new_message"><item quantity="one">%1$d new message</item><item quantity="other">%1$d new messages</item></plurals>
</resources>

要将复数形式作为 a 访问,请使用以下代码:String

From 可组合代码

@Composable
fun pluralStringResource(resource: PluralStringResource, quantity: Int): String {...}@Composable
fun pluralStringResource(resource: PluralStringResource, quantity: Int, vararg formatArgs: Any): String {...}

从不可组合代码

suspend fun getPluralString(resource: PluralStringResource, quantity: Int): Stringsuspend fun getPluralString(resource: PluralStringResource, quantity: Int, vararg formatArgs: Any): String

例如:

coroutineScope.launch {val appName = getPluralString(Res.plurals.new_message, 1, 1)
}

字体

自定义字体存储在目录中 or files.composeResources/font*.ttf*.otf

要将字体加载为类型,请使用以下函数:Font Font()

@Composable
fun Font(resource: FontResource,weight: FontWeight = FontWeight.Normal,style: FontStyle = FontStyle.Normal
): Font

例如:

val fontAwesome = FontFamily(Font(Res.font.font_awesome))

Raw 文件

要将任何原始文件加载为字节数组,请使用以下函数:Res.readBytes(path)

suspend fun readBytes(path: String): ByteArray

您可以将原始文件放在目录中,并在其中创建任何层次结构。composeResources/files

例如,要访问原始文件,请使用以下代码:

From 可组合代码

var bytes by remember {mutableStateOf(ByteArray(0))
}
LaunchedEffect(Unit) {bytes = Res.readBytes("files/myDir/someFile.bin")
}
Text(bytes.decodeToString())

从不可组合代码

coroutineScope.launch {val bytes = Res.readBytes("files/myDir/someFile.bin")
}
将字节数组转换为图像

如果您正在读取的文件是位图(JPEG、PNG、BMP、WEBP)或 XML 矢量图像,则可以使用以下函数将它们转换为适合可组合项的对象。ImageBitmap ImageVector Image()

访问 Raw 文件部分所示的原始文件,然后将结果传递给可组合项:

// bytes = Res.readBytes("files/example.png")
Image(bytes.decodeToImageBitmap(), null)// bytes = Res.readBytes("files/example.xml")
Image(bytes.decodeToImageVector(LocalDensity.current), null)

在除 Android 之外的所有平台上,您还可以将 SVG 文件转换为对象:Painter

// bytes = Res.readBytes("files/example.svg")
Image(bytes.decodeToSvgPainter(LocalDensity.current), null)

为资源和字符串 ID 生成的映射

为了便于访问,Compose Multiplatform 还使用字符串 ID 映射资源。您可以使用文件名作为键来访问它们:

al Res.allDrawableResources: Map<String, DrawableResource>
val Res.allStringResources: Map<String, StringResource>
val Res.allStringArrayResources: Map<String, StringArrayResource>
val Res.allPluralStringResources: Map<String, PluralStringResource>
val Res.allFontResources: Map<String, FontResource>

将映射的资源传递给可组合项的示例:

Image(painterResource(Res.allDrawableResources["compose_multiplatform"]!!), null)

将多平台资源组合为 Android 资产

从 Compose Multiplatform 1.7.3 开始,所有多平台资源都打包到 Android 资产中。这样,Android Studio 就可以在 Android 源代码集中为 Compose Multiplatform 可组合项生成预览。

Android Studio 预览仅适用于 Android 源代码集中的可组合项。它们还需要最新版本的 AGP 之一:8.5.2、8.6.0-rc01 或 8.7.0-alpha04。

使用多平台资源作为 Android 资产还可以从 Android 上的 WebView 和媒体播放器组件直接访问,因为资源可以通过简单的路径访问,例如 .Res.getUri("files/index.html")

Android 可组合项显示带有资源图片链接的资源 HTML 页面的示例:

// androidMain/kotlin/com/example/webview/App.kt
@OptIn(ExperimentalResourceApi::class)
@Composable
@Preview
fun App() {MaterialTheme {val uri = Res.getUri("files/webview/index.html")// Adding a WebView inside AndroidView with layout as full screen.AndroidView(factory = {WebView(it).apply {layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT)}}, update = {it.loadUrl(uri)})}
}

该示例适用于以下简单的 HTML 文件:

<html>
<header><title>Cat Resource</title>
</header>
<body><img src="cat.jpg">
</body>
</html>

此示例中的两个资源文件都位于源集中:commonMain

与其他库和资源的交互

从外部库访问多平台资源

如果要使用项目中包含的其他库处理多平台资源,则可以将特定于平台的文件路径传递给这些其他 API。要获取特定于平台的路径,请使用资源的工程路径调用函数:Res.getUri()

val uri = Res.getUri("files/my_video.mp4")

现在,变量包含文件的绝对路径,任何外部库都可以使用该路径以适合它的方式访问文件。uri

对于特定于 Android 的用途,多平台资源也打包为 Android 资产。

远程文件

在资源库的上下文中,只有属于应用程序的文件才被视为资源。

您可以使用专用库使用 Internet 的 URL 从远程文件加载远程文件:

  • 编写 ImageLoader

  • Kamel

  • Ktor 客户端

使用 Java 资源

虽然您可以将 Java 资源与 Compose Multiplatform 结合使用,但它们无法从框架提供的扩展功能中受益:生成的访问器、多模块支持、本地化等。考虑完全过渡到多平台资源库以释放这种潜力。

在 Compose Multiplatform 1.7.3 中,软件包中提供的资源 API 已弃用。如果您仍需要使用 Java 资源,请将以下实现复制到您的项目中,以确保您的代码在升级到 Compose Multiplatform 1.7.0 或更高版本后仍能正常工作:compose.ui

@Composable
internal fun painterResource(resourcePath: String
): Painter = when (resourcePath.substringAfterLast(".")) {"svg" -> rememberSvgResource(resourcePath)"xml" -> rememberVectorXmlResource(resourcePath)else -> rememberBitmapResource(resourcePath)
}@Composable
internal fun rememberBitmapResource(path: String): Painter {return remember(path) { BitmapPainter(readResourceBytes(path).decodeToImageBitmap()) }
}@Composable
internal fun rememberVectorXmlResource(path: String): Painter {val density = LocalDensity.currentval imageVector = remember(density, path) { readResourceBytes(path).decodeToImageVector(density) }return rememberVectorPainter(imageVector)
}@Composable
internal fun rememberSvgResource(path: String): Painter {val density = LocalDensity.currentreturn remember(density, path) { readResourceBytes(path).decodeToSvgPainter(density) }
}private object ResourceLoader
private fun readResourceBytes(resourcePath: String) =ResourceLoader.javaClass.classLoader.getResourceAsStream(resourcePath).readAllBytes()

下一步是什么?

查看官方演示项目,该项目展示了如何在面向 iOS、Android 和桌面的 Compose Multiplatform 项目中处理资源。

相关文章:

【Compose multiplatform教程20】在应用程序中使用多平台资源

为项目设置资源后&#xff0c;生成项目以生成提供资源访问权限的特殊类。要重新生成类和所有资源访问器&#xff0c;请再次生成项目或在 IDE 中重新导入项目。ResRes 之后&#xff0c;您可以使用生成的类从您的代码或外部库访问配置的多平台资源。 自定义访问器类生成 您可以使…...

深入浅出:从入门到精通大模型Prompt、SFT、RAG、Infer、Deploy、Agent

阅读原文 渐入佳境 我们都知道&#xff0c;通过编写一个提示词&#xff08;prompt&#xff09;&#xff0c;我们可以引导大模型生成回答&#xff0c;从而开启愉快的人工智能对话&#xff0c;比如让模型介绍一下卡皮巴拉。上边简图描述了这个过程&#xff0c;我们拆成两部分 pr…...

紫光同创-盘古200pro+开发板

本原创文章由深圳市小眼睛科技有限公司创作&#xff0c;版权归本公司所有&#xff0c;如需转载&#xff0c;需授权并注明出处&#xff08;www.meyesemi.com) 一、开发系统介绍 开发系统概述 MES2L676-200HP 开发板采用紫光同创 logos2 系列 FPGA&#xff0c;型号&#xff1a;…...

iOS 中的 nil、Nil、NULL、NSNull 僵尸对象和野指针

iOS 中的 nil、Nil、NULL、NSNull 僵尸对象和野指针-CSDN博客 类型含义使用场景示例nil表示一个指向 Objective - C 对象的空指针。在 Objective - C 和 Swift&#xff08;与 Objective - C 交互时&#xff09;中用于表示对象不存在。当一个对象变量没有指向任何有效的对象实例…...

【优选算法】有效三角形的个数(双指针算法)

优质专栏&#xff1a;算法_云边有个稻草人的博客-CSDN博客 目录 【611. 有效三角形的个数 - 力扣&#xff08;LeetCode&#xff09;】 解法一&#xff1a; 解法二&#xff1a; 【611. 有效三角形的个数 - 力扣&#xff08;LeetCode&#xff09;】 解法一&#xff1a; 三层for…...

中介者模式(Mediator Pattern)、桥接模式(Bridge Pattern) 和 策略模式(Strategy Pattern)

中介者模式&#xff08;Mediator Pattern&#xff09;、桥接模式&#xff08;Bridge Pattern&#xff09; 和 策略模式&#xff08;Strategy Pattern&#xff09; 都是常见的设计模式&#xff0c;它们解决不同类型的问题。我们将通过 Swift 示例来说明它们的使用场景&#xff0…...

客户案例:基于慧集通打通聚水潭电商ERP与用友U8系统集成之路

一、引言 本原型客户是 生物科技公司&#xff0c;其公司系列抗菌抗病毒产品广泛应用于医疗用品、纺织服饰、家纺用品、母婴护理、女性用品、个人防护等多个领域。在知识产权方面&#xff0c;公司在专业领域已获得商标和专利近百项&#xff0c;创新能力得到了国家及行业内普遍认…...

阿里云clb是什么

传统型负载均衡服务 ‌阿里云CLB&#xff08;Classic Load Balancer&#xff09;是阿里云提供的一种传统型负载均衡服务&#xff0c;主要用于将访问流量根据转发策略分发到后端多台云服务器。‌‌ CLB的定义和功能 CLB是一种流量分发控制服务&#xff0c;通过设置虚拟服务地…...

【Cursor编辑器】自用经验和实操(迭代更新)

1.启动composer crtl I 2.生成直接一直问加载 3. 实操 生成个知识图谱&#xff0c;使用csv文件里面的数据创关系和节点。...

【学习笔记】ChatGPT原理与应用开发——基础科普

HuggingLLM&#xff08;ChatGPT原理与应用开发&#xff09; 原文链接&#xff1a;HuggingLLM&#xff08;ChatGPT原理与应用开发&#xff09;-课程详情 | Datawhale 此处仅为学习记录和总结 1&#xff1a;基础科普 1.1&#xff1a;自然语言背景 图灵测试 如果一个人&#x…...

基于Web的实验中心工作管理网站的设计与实现

写作任务 一、课题背景 实验中心承担了全校计算机公共基础课程和学院专业课程&#xff0c;需要对实验中心工作进行有效的管理。 二、课题任务 本课题设计和实现实验中心工作管理系统。 系统的主要内容包括&#xff1a; &#xff08;1&#xff09;人员管理&#xff1b; &am…...

docker 安装minio

docker pull minio/minio #启动 mkdir -p /root/minio/config mkdir -p /root/minio/datadocker run -d \--name minio \-p 9002:9000 \-p 9001:9001 \--restartalways \-v /root/minio/data:/data \-v /root/minio/config:/root/.minio \-e "MINIO_ACCESS_KEYminioadmin…...

ubuntu下ipmi的使用(4028)

参考ubuntu系统下配置IPMI_ubuntu ipmi-CSDN博客 参考&#xff1a;ipmitool ubuntu 安装_ipmi centos ubuntu使用总结-CSDN博客 1.安装 sudo apt-get -y install ipmitool 2.加载 modprobe ipmi_msghandlermodprobe ipmi_devintfmodprobe ipmi_si 3.使用,查看不到的话&am…...

周记-唐纳德的《计算机程序设计艺术》

用代码生成代码 开发一个协议&#xff0c;字段有些多&#xff0c;每个字段是QT的属性&#xff0c;需要写Q_PROPERTY&#xff0c;一个一个编辑的话比较繁琐&#xff0c;耗费时间。后来就用代码生成了头文件和源文件&#xff0c;get和set还有signal函数&#xff0c;内容基本都是…...

极品飞车6的快捷键与车辆等级

极品飞车&#xff0c;英文全称为Need for Speed&#xff0c;是EA公司于1994年开始研发的赛车类竞技游戏。从1996年的《极品飞车-特别版》、2002年的《极品飞车:闪电追踪2》、2005年的《极品飞车:地下狂飙2》、到2024年《极品飞车:集结》&#xff0c;是70后、80年、90年等几代人…...

计算机毕业设计Python+知识图谱大模型AI医疗问答系统 健康膳食推荐系统 食谱推荐系统 医疗大数据 机器学习 深度学习 人工智能 爬虫 大数据毕业设计

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…...

纯真社区版IP库CZDB数据格式使用教程

1. 概述 纯真社区版IP库是一种免费且公开的IP地理位置数据库&#xff0c;主要面向非商业用途。其最新推出的CZDB格式是一种全新的数据文件格式&#xff0c;自2024年10月起将成为官方维护和更新的唯一版本。该格式支持同时存储IPv4和IPv6地址信息&#xff0c;具备以下优点&…...

Linux(Centos 7.6)软件包安装

Linux软件安装&#xff0c;常见的有三种方式&#xff0c;rpm方式、yum方式、源码编译安装方式。其中rpm方式可能存在依赖方式&#xff0c;可能会比较麻烦&#xff1b;源码编译安装同样可能会缺少一些编译需要的软件需要安装&#xff0c;也会比较麻烦&#xff1b;相对比较好的方…...

[WASAPI]音频API:从Qt MultipleMedia走到WASAPI,相似与不同

[WASAPI] 从Qt MultipleMedia 来看WASAPI 最近在学习有关Windows上的音频驱动相关的知识&#xff0c;在正式开始说WASAPI之前&#xff0c;我想先说一说Qt的Multiple Media&#xff0c;为什么呢&#xff1f;因为Qt的MultipleMedia实际上是WASAPI的一层封装&#xff0c;它在是线…...

【畅购商城】微信支付之支付模块

目录 支付页面 接口 后端实现 前端实现​​​​​​​ ​​​​​​​支付页面 步骤一&#xff1a;创建 flow3.vue组件 步骤二&#xff1a;引入第三方资源&#xff08;js、css&#xff09; <script> import TopNav from ../components/TopNav import Footer from …...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在 GPU 上对图像执行 均值漂移滤波&#xff08;Mean Shift Filtering&#xff09;&#xff0c;用于图像分割或平滑处理。 该函数将输入图像中的…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合

在汽车智能化的汹涌浪潮中&#xff0c;车辆不再仅仅是传统的交通工具&#xff0c;而是逐步演变为高度智能的移动终端。这一转变的核心支撑&#xff0c;来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒&#xff08;T-Box&#xff09;方案&#xff1a;NXP S32K146 与…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行

项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战&#xff0c;克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

Java编程之桥接模式

定义 桥接模式&#xff08;Bridge Pattern&#xff09;属于结构型设计模式&#xff0c;它的核心意图是将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。这种模式通过组合关系来替代继承关系&#xff0c;从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

虚拟电厂发展三大趋势:市场化、技术主导、车网互联

市场化&#xff1a;从政策驱动到多元盈利 政策全面赋能 2025年4月&#xff0c;国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》&#xff0c;首次明确虚拟电厂为“独立市场主体”&#xff0c;提出硬性目标&#xff1a;2027年全国调节能力≥2000万千瓦&#xff0…...

AI语音助手的Python实现

引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...

【UE5 C++】通过文件对话框获取选择文件的路径

目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 &#xff0c;这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器&#xff0c;右键点击 .uproject 文件&#xff0c;选择 "Generate Visual Studio project files"&#xff0c;重…...