WWDC 2020 - Swift Package Manager
source link: https://kemchenj.github.io/2020-06-29/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
虽然 Swift Package Manager 发布到现在已经四年了,但采用率一直很低,无法完全替代 Cocoapods,不过今年情况将会有所改善,SwiftPM 今年迎来两个非常重要的功能:
- 二进制依赖分发
- 资源文件
二进制依赖
在去年 Xcode 11 集成了 SwiftPM 的功能,让我们可以以源码形式分发 Library,并且也引入了 XCFramework 来分发闭源 Library。
今年 Xcode 12 将会把它们结合到一起,提供二进制依赖库的支持,在下面的章节里我们将会介绍如何集成,分发和制作二进制依赖。
集成
包含了二进制文件的 Swift Package 在集成时不需要任何特殊的设置,它们也是一个普通的 Package.product
,像之前一样在 target 的 dependencies
里通过名字指定即可:
let package = Package( name: "package", products: [ .executable(name: "package", targets: ["package"]) ], dependencies: [ .package("https://github.com/JohnnyAppleased2020/BinaryEmoji", from: "1.0.0") ], targets: [ .target(name: "package", dependencies: ["Emoji"]) ] )
分发
需要注意,二进制依赖在 Swift 5.3 及以上才能使用:
// swift-tools-version: 5.3
Swift 5.3 里新增了一种新的 Target
类型 binaryTarget
来指定打包好的二进制文件:
let package = Package( name: "Emoji", products: [ .library(name: "Emoji", targets: ["Emoji"]), ], targets: [ .binaryTarget( name: "Emoji", url: "https://example.com/emoji/Emoji-1.0.0.xcframework.zip", checksum: "6d9888a1a27418674b4d7c31732f6d60e60734ceb11a0ce9b54d1871918d9c194" ) ] )
在分发二进制依赖时需要注意几点:
- 目前只支持苹果平台,为了实现的便捷复用了已有的 XCFramework 格式,它支持动态和静态链接,并且可以同时支持多个平台。
- 支持本地路径或者 https 链接。
- 在使用本地路径时指向的可以是 XCFramework 的路径或者是 XCFramework 压缩后的 zip 文件,而 https 链接则只能指向 zip 文件。
制作
目前 XCFramework 的制作必须依托于 xcodebuild
,所以需要先使用 swift package generate-xcodeproj
生成 Xcode 项目文件,然后:
- 在 Build Settings 里将
Build Libraries for Distribution
选项改为YES
。 - 使用
xcodebuild archive
打包 framework 文件。 - 使用
xcodebuild -create-xcframework
将各个平台的 framework 文件合并为 xcframework。
更具体的细节可以查看 Binary Frameworks in Swift - WWDC2019 。
资源文件
今年的 Xcode 12 我们可以给 Swift Package 添加图片,storyboard 以及其它资源文件,同时也可以本地化这些资源文件。并且资源文件的添加使用的是现有的 API,所以也兼容之前版本的操作系统。
添加资源文件
SwiftPM 会根据文件的拓展名来进行处理,有一部分文件的使用目的非常明确,Xcode 会自动帮我们处理,只要添加到目录里即可:
但有一部分文件它们的使用目的并不明确,例如 shell 脚本,文件夹,它们可能并不需要打包到 Package 里,此时我们就需要手动声明这些文件的处理规则:
接下来让我们通过一个例子来了解具体的操作,重新回顾一下 Swift Package 的目录结构,我们会在 Sources 文件夹里看到与 target 同名的目录,目录里会存放着这个 target 的所有代码文件:
更具体的规则大家可以查看 Adopting Swift Packages in Xcode - WWDC19 。
接着我们来看 GameLogic 目录的结构,下面我们可以看到 storyboard 和 xcassets 不需要做任何的额外声明,直接添加到对应的目录里即可。
但 Internal Notes.txt 有些特别,它只是开发过程中使用的文档,我们不希望它也被打包到 Package 里,此时我们可以通过 excludes
参数进行指定:
如果我们要添加一些运行时需要的资源文件,就可以通过 resources
参数进行指定,大部分资源文件都可以使用 process
指定,此时它们会根据对应的平台和打包方式自动进行处理:
有时我们需要目录在打包到 Package 之后也能保持它的结构,那么此时就可以使用 copy
选项:
.process
选项会使用 SwiftPM 预设的规则自动进行处理:
.copy
.copy
没有规则,只是单纯的复制:
- 可以用来覆盖预设的规则。
- 目录的复制会递归进行(深复制)。
访问资源文件
资源文件的访问会沿用现有的 Foundation.Bundle
,这意味着 macOS 和 Linux 都可以共享同一套代码。
SwiftPM 会给所有带资源文件的 Target 自动合成当前 Bundle
的声明:
Bundle.module SWIFTPM_MODULE_BUNDLE
访问资源文件:
// Swift let image = UIImage(named: "Logo", in: Bundle.module) // Objective-C UIImage *image = [UIImage imageNamed:@"Logo" inBundle:SWIFTPM_MODULE_BUNDLE];
需要注意:warning:, Bundle.module
会被声明为 internal:
extension Bundle { internal var module: Bundle { get } }
如果要让外部也能访问 Package 内的资源文件,推荐框架作者提供类型安全的外部接口。
本地化
Package 内的资源文件也支持本地化,我们需要在 Package.swift 声明默认的语言 defaultLocalization
:
let package = Package( name: "DiceUI", defaultLocalization: "en", ... )
存放资源的目录名称需要使用对应的 Language ID + Locale ID + .lproj
,例如 en.lproj
。
Language and Locale ID - developer.apple.com
本地化的资源通常是:
.strings .stringDicts
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK