大多数浏览器和
Developer App 均支持流媒体播放。
-
Swift 软件包资源和本地化
在你使用 Swift 软件包进行组织和共享 Swift 代码时,请带上你的资源。了解如何在软件包中加入图像和 storyboard 等素材,以及如何从代码中访问这些素材。并学习如何添加本地化字符串,让世界各地的人都可访问你的代码。 要想充分利用本节内容,建议先熟悉 Swift 和打包代码。获取内容概要,请观看 WWDC19 中的“创建 Swift 包”。
资源
相关视频
WWDC22
WWDC20
WWDC19
-
下载
(你好 WWDC 2020) 你好 欢迎来到 WWDC (Swift 软件包资源和本地化) 我是 Anders 今天我来谈谈 Swift 软件包资源和本地化 首先 我们会看看如何将资源 添加到 Swift 软件包里 接下来 我们会介绍包创建好后 会发生的情形 以及在运行时 包里的代码如何使用资源 最后 我们会了解如何本地化 包里的资源
我们从将资源添加到包开始吧 Xcode 11 为Swift 软件包引入了支持 使你能够在 Xcode 项目中 创建包并使用现有的包 你可以在 Swift 中 或在任何 C 语言中执行包 在 Xcode 12 中 你可以将如下资源 比如图像、Storyboard 和其他文件添加到包里
你也可以将这些资源本地化 这样国际化的 app 就可以利用你的包提供的功能 往包里添加资源对现有的 API 也行得通 所以它不会影响你的包的 OS 版本要求 (没有特殊运行要求) 我们来看看这些是怎么实现的 现在我有一个执行 SwiftUI 视图的包 它显示了骰子的侧面 并有一个让你滚动骰子的按钮 Xcode 12 中的一个创新是 它可以为包里的 SwiftUI 视图显示预览 而不用在同一个工作区有一个客户端 app 但如大家所见 这里缺了点什么 这个包视图显示的是黑框 而不是骰子上的点 当我点击按钮滚动骰子时 它会选择新的点数 但不会显示它 我们来调整一下 我要在 DiceUI 目标里 紧挨着源代码的地方创建一个资产目录
由于其文件名后缀 Xcode 会知道它是个资产目录 并知道如何处理它 资产目录开始为空 但我要添加几张在三个不同分辨率下 显示带有不同点数的骰子图像
接下来我进入该视图的应用阶段 我用一个图像替换矩形视图
我选择了图像的名称 所以它们与点数名称匹配 这样我就可以把名称传给初始化器
我要指定一个 bundle 参数 以指示图像应该来自 我的代码构建到其中的 模块的资源 bundle
包资源使用现有 bundle 类型的 Foundation API 来访问资源 这样你就可以把它 传给任何采用 bundle 参数的 API 我们一会儿 好好了解一下这是怎么运作的 然后我看到骰子的图像显示出来了
我点击“滚动”按钮 我可以看到它选择了不同的点数 现在我其实可以删除这里的 bundle 部分 因为有了 Swift 类型推断 我只有“.module”就行
在此我们看到了你可以如何轻易 将资源添加到 Swift 软件包里 以及如何在 Xcode 中 在包上工作时显示预览 (资源文件类型) 包里的文件是根据其类型进行处理的 如文件名后缀所示 一些类型的文件 比如资产目录、Storyboard 和 Core Data 模型 都有明确的目的 这些类型的文件可以直接被添加到包里 Xcode 知道怎么处理它们
其他类型的文件会有各种目的 普通文本文件可能在运行时会被需要 或者可能仅在开发期间被用到 图像、Shell 脚本 和其他常见类型文件也是如此
对于这种类型的文件 你需要在包清单中声明其目的 我们来看一个例子 这是一个名为 MyGame 的 示例包的文件系统结构 有个名为 GameLogic 的单目标 目标的所有源文件 都位于 Sources 目录下 在与目标同名的子目录中
我们看看包清单文件的内容 就会看到 GameLogic 目标的相应产品 和目标定义
我们要在这里明确怎么处理 那些目的不明确的目标文件
要想进一步了解包清单的语法 以及它与文件系统结构是如何关联的 请观看 WWDC 19 讲座的 《在 Xcode 中引入 Swift 软件包》
我们来专注于目标目录 所有目标的源和资源都位于其下 这里已经有了一个 Swift 源文件 而且其目的很明确 在构建包时应对其进行编译 清单中我们不需要任何额外内容 现在我们来添加资产目录 资产目录是有明确文件名后缀 和结构的目录 它会在创建时被处理 并被包含在包的客户端中 在清单中 我们不需要任何特殊东西 如果我们添加一个 storyboard 也是如此 它也有明确的目的 并会以 Xcode 项目中同样的方式被编译
接下来 我们来添加一个普通文本文件
现在情况变得更有趣了 文本文件可被用于各种情况 所以 Xcode 应该怎么处理它不是很明显 也许它是用于运行的资源 也许它只是一些内部开发备忘录 在这个例子中 我们不希望 Xcode 把它当成资源对待 我们将其添加到清单中的排除文件列表中 这样会致使其在构建包时被忽视
我们也可以添加一个 全是文件和文件夹的目录 比如游戏中用以创建艺术作品的 草图和设计文档 对于一个文件 我们可以把目录的名称或者子路径 添加到清单中的排除列表中 这样会导致该目录及其下面的内容 在构建包时被跳过
现在我们来添加一个独立的图像文件 在这种情况下 运行时我们会需要它 所以我们将其作为资源添加到清单中 并且我们为其指定处理操作
大部分资源应该使用该处理操作 这样在构建时 它们就会被进行适当转化 会进行的确切处理类型 取决于构建包的平台
现在我们来添加一个我们的示例游戏 在运行时所需要的满是文件的目录 在这种情况下 其下有整个文件和文件夹的层次结构
我们希望在运行时 所有这些都可用 包括目录结构 所以我们将其声明为资源 但这次 我们指定“复制”操作 这样会致使其完全照原样被复制 保留其目录结构
现在我们了解了 如何把几种不同类型的文件 添加到包目标 了解了对于出现 文件类型不明确的情况后 如何声明其目的
正如大家所见 任何资源都可以逐字节地被处理或被复制 “处理”操作通常是我们推荐的选择 因为它会针对平台 应用适当的 内置规则 这可能包括将 storyboard 或资产目录 转换成适合在运行时使用的形式 或者可能包括压缩图像等等
如果文件类型未知 或者平台不需要特殊处理 那么文件就会被复制
处理规则以递归方式应用于 目录下的每个文件 每个生成的输出文件作为单独资源 被包含在产品中
当你想要准确复制资源时 不管其类型如何 “复制”操作都是合适之选
复制根本不执行任何转换 比如说 如果你想将其用作 运行时的模板 那么它可以被用来 复制通常已被编译的源文件
如果你想包括整个的目录 并保留其层次结构 那也可以使用复制操作 (资源处理) 当目标构建后 里面的文件会发生什么? 比如 我们有个包和使用该包的 app 该包含有源文件和资源文件 每个目标的源都被编译进一个代码模块里 并被链入客户端 app 每个目标的资源 都被处理到该模块的资源 bundle 中 然后被嵌入到该 app 中
在 Apple 平台上 app 和 app 扩展就是 bundle 所以无需执行其他操作 每个包模块的资源 bundle 都是 app bundle 的一部分 因此在运行时可用
在创建非绑定产品时 比如命令行工具 资源 bundle 会需要随该工具安装
关于包清单 还有一点需注意 也就是最小工具版本 Swift Package Manager 是 Swift 工具链的一部分 对包资源的支持是 Swift 5.3 的新亮点 因此包清单需要声明 5.3 作为其要求的工具版本 但这个是如何与 Xcode 版本关联的?
每个 Xcode 发行版本 都包括 Swift 工具链的一个版本 Xcode 11 是第一个支持 Swift 软件包的版本 其 Swift 工具链版本是 5.1 在 Xcode 12 中 包括的 Swift 工具链 版本是 5.3 工具版本应该被设为 支持包所需功能的最低版本 这是因为任何使用它的包或项目 也会需要具有该工具版本或更高版本 以便构建包 现在我们已将资源添加到该包 接下来我们来聊聊如何从代码中访问它们 如大家所见 你使用 Foundation 的 Bundle API 以在运行时访问包资源
Foundation 在支持 Swift 软件包的 所有平台都可用 所以这样提供了一种一致的 与平台无关的 访问资源的方式 无论构建系统为特定平台 创造出了什么样的工件 (从代码访问资源) 当 Xcode 创建一个包含资源的包目标后 它会为资源 bundle 合成一个访问器 并将其包含在为目标创建的代码模块中 该模块就可以访问其资源 bundle 无论是在 Swift 中 还是在 Objective-C 中执行
返回的 bundle 对象仅限于每个代码模块 但你在源代码中访问它的方式始终一样
这是使用 Bundle API 访问 Swift 和 Objective-C 资源 bundle 里的 文件的一个例子
在两种语言中 访问器返回 一个 Foundation Bundle 对象 其可被用来按名称查找资源
但资源 bundle 也可以被传给 任何以 bundle 为参数的系统 API
在此处显示的例子中 它被传给 UIImage 方法 这样可以查找包资源 bundle 的图像
当将资源添加到包时 你应该将其添加到 使用其代码模块的目标中 资源 bundle 访问器仅对与资源 位于同一模块中的代码可见 如果你需要将资源提供给其他模块 最好通过添加提供单独资源的 特定类型访问器来实现 我们通常不推荐 将整个资源 bundle 提供给其他模块 因为那样会对资源的特定名称 产生外部依赖
Xcode 12 也使你能够将本地化的资源 添加到你的包里 我们来瞧瞧之前看到的 本地化示例包中的文本
首先我要做的是 将 defaultLocalization 参数 添加到我的包清单中
这样声明了我在开发过程中所使用的语言 如果没有更好的匹配项 它会被用作 运行时的应变本地化语言 这个对于任何包含资源的包都是必需的
接下来 我要为我的默认本地化语言英语 创建一个本地化目录
并将其命名为“en.lproj”
在内部 我创建了一个名为 “Localizable.strings”的文件
我将一个条目添加到字符串文件 这个文件仅将我在代码中使用的 可本地化的字符串键 映射到英语单词“ roll”
接下来我要进行同样的操作 不过是针对法语 我创建了一个名为“fr.lproj”的目录 并在里面创建了一个 “Localizable.strings”文件
在这个文件中 我要将英语字符串密钥里的映射…
添加到这个单词的法语翻译 接下来 就像我对图像视图的操作一样 我要对文本视图进行同样的操作 也就是为包含我的代码的模块 递交资源 bundle 这个使用 Foundation 对本地化的支持 根据用户选择的语言 找到正确的本地化内容
预览仍以英语显示 这是因为我的系统语言是英语 但借助 SwiftUI 我们可以自定义预览 例如 我们可以添加环境超控 以在预览中查看法语本地化 我们可以看到它使用的 是生成的资源 bundle 里 本地化的字符串
正如演示所示 本地化目录有“.lproj”文件名后缀 本地化目录可以被包含进包目标中 而不用在清单中提及它们 因为“.lproj”后缀使其目的很明确
一个本地化目录通常包含字符串文件 和用于翻译文本的字符串代码字典文件 但它也可以在包中包含 单独资源的自定义版本
也可以本地化资产目录的内容 这样你可以在适当的情况下 为特定的本地化提供不同的 艺术作品
你可以从 WWDC 19 《打造出色的本地化体验》讲座中 了解更多这方面的内容
当你将本地化资源添加到包时 你需要在包清单中 声明默认的本地化语言
这个使用的语言 ID 和在 Apple 平台 用于所有本地化的语言 ID 是一样的 并在没有首选语言可用的情况下 指定用作最后手段的语言
在 developer.apple.com 网站上的 《语言和区域 ID》文档中 你可以找到关于此话题的更多信息
在本视频中 我们了解了如何将资源 添加到 Swift 软件包中 以及 Xcode 如何创建资源 bundle 让你能在运行时访问这些资源 我们也了解了如何本地化你包里的资源
Xcode 使你能够创建 Swift 软件包 并同时利用 现有包强大且不断发展的的生态系统 Xcode 12 通过让你 即便在没有客户端 app 的情况下 与视图互动 使得开发包含 SwiftUI 视图的包更简单 对本地化包资源的支持 使你创建出的包 功能可供世界各地的人们使用 谢谢 请欣赏 WWDC 20 的其他内容
-
-
4:09 - Package Manifest file
// swift-tools-version:5.3 import PackageDescription let package = Package(name: "MyGame", products: [ .library(name: "GameLogic", targets: ["GameLogic"]) ], targets: [ .target(name: "GameLogic", excludes: [ "Internal Notes.txt", "Artwork Creation"], resources: [ .process("Logo.png"), .copy("Game Data")] ) ] )
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。