Swift Package Manager 使用指南

Viewed 0

Swift Package Manager (SPM) 包管理器

SPM(Swift Package Manager)是管理 Swift 代码分发的工具,用于处理模块代码的下载、编译和依赖关系。它类似于 CocoaPods,但更简洁,代码侵入性更小,也不需要额外安装工具。

SPM依赖安装

Xcode 自带 SPM,可以在终端上查看 SPM 版本:

$ swift package --version
Swift Package Manager - Swift 5.3.0

新建一个项目(例如 SPMTest),添加 SPM 依赖。在 Xcode 中,选择 File -> Swift Packages -> Add Package Dependency...,或者进入 PROJECT -> Swift Packages 点击加号添加依赖。

输入需要添加的第三方库的链接,点击下一步等待验证成功。根据实际需要选择版本,有三个选项:

  • Version: 对应库的 Release 版本,可选择版本规则,自动下载规则内最新版本。
    • Up to Next Major: 指定一个主要版本的范围,例如 5.4.2~6.0.0。
    • Up to Next Minor: 指定一个小版本范围,例如 5.4.2~5.5.0。
    • Range: 指定一个版本范围,例如 5.4.1~5.5.1。
    • Exact: 指定一个确切的版本,例如 5.4.1。
  • Branch: 直接下载某个分支的代码。
  • Commit: 根据某一次提交记录的 ID 下载。

添加完成后,项目中会出现 Swift Package Dependencies 目录,这样就可以在项目中直接使用这个第三方依赖库了。要更新 SPM 中的依赖,选择 File -> Swift Packages -> Update to Latest Package Versions。如果想要修改某个第三方库的版本策略,可以双击第三方库进行修改。

创建本地Swift Package库

新建一个 Swift Package。打开项目 SPMTest,选择 File -> New -> Swift package...,把这个包命名为 ZZPackage,并添加到现有的项目中。新建完成后,在项目工程中包含了 ZZPackage 这个 Package。

如何引入 ZZPackage 到工程中并使用其中的功能模块?

Targets -> General -> Frameworks, Libraries, and Embedded Content 部分,点击 + 号,添加 ZZPackage。这样就把 ZZPackage 引入到项目中了。

ZZPackage 下的 Sources/ZZPackage 目录下新建 ExView.swift,然后在工程中使用这个文件中的方法:

import SwiftUI

extension View {
    // module对外的访问权限设为public
    public func printLog(_ value: Any) -> some View {
        #if DEBUG
        print(value)
        #endif
        return self
    }
}

直接编译可能会报错,因为代码使用了 SwiftUI,需要 iOS 13 及以上。可以在 Package.swift 中添加 platforms: [.iOS(.v13)],或在扩展代码上面添加 @available(iOS 13.0, *)。这两种方式都可以编译成功。

发布你的 Swift Package

找到 SPMTest 文件夹下的 ZZPackage 文件夹,上传库到云端(如 GitHub、Gitee 或其他托管服务器)。然后设置 Tag 版本号就可以了。删除本地 Package,就可以通过仓库地址加载远程 Package。

发布后远程加载

打 tag 发布到 GitHub 后,在 File > Add Packages 的搜索中输入地址。如果搜索加载报错,可以换一种方式加载:创建本地 Package 关联项目,然后添加远程依赖。

  1. 选择 File > New > Package
  2. 把新建的 Swift Package 添加到已有的项目中,Package 保存为 Library
  3. Targets -> General -> Frameworks, Libraries, and Embedded Content 部分,点击 + 号添加 Library,然后编译。
  4. 添加其他远程依赖库,例如添加 STNavigationController。它会自动加载依赖,加载成功后就可以在项目中使用依赖的库了。

SPM文件及配置

SPM 的主要文件和配置包括:

  • Source 文件夹:第三方库源码位置路径文件。
  • Package.swift:SPM 配置文件。

查看 Package.swift 文件:

// swift-tools-version:5.3

import PackageDescription

let package = Package(
    name: "ZZPackage",
    platforms: [.iOS(.v13)],
    products: [
        .library(
            name: "ZZPackage",
            targets: ["ZZPackage"]),
    ],
    dependencies: [],
    targets: [
        .target(
            name: "ZZPackage",
            dependencies: []),
        .testTarget(
            name: "ZZPackageTests",
            dependencies: ["ZZPackage"]),
    ]
)

第一行是 Swift Tools 的版本,这里是 swift 5.3 版本。这行注释说明了构建 swift package 所需最低的 swift 版本号。然后导入了 PackageDescription,这个库提供了配置 swift package 所需的 API。

  • name: 包的项目名称。
  • platforms: 支持的平台及对应平台的最低版本。
  • targets: 包含多个 target 的集合。指定 target 的名字为 ZZPackage,Xcode 会自动把 Sources/ZZPackage 目录下的所有文件添加到 package 中。如果想新建一个 target,需要在 Sources/ 目录下新建一个文件夹,然后在 targets 数组中添加新的 target。
  • products: 对外公开导出 target 产物,使得其他 target 能够使用它们。如果不写会编译报错。例如 .library(name: "ZZPackage", type: .static, targets: ["ZZPackage"]),可指定静态库或动态库,默认静态库。
  • dependencies: 添加包所依赖的其他第三方 package 包的集合。例如:
    • .package(url: "https://github.com/Alamofire/Alamofire.git", from: "5.0.0")
    • .package(url: "https://github.com/SnapKit/SnapKit.git", from: .init(5, 0, 1))
    • .package(url: "https://github.com/SnapKit/SnapKit.git", Package.Dependency.Requirement.branch("master")):指定分支,如果第三方不支持 SPM 可以使用这种方式。
    • .package(path: "../ZZPackage"):关联本地的 SPM 库。
  • swiftLanguageVersions: 支持的 swift 版本。

resources 添加资源文件

.target 下,可以添加资源文件字段 resources。例如添加图片资源自定义文件夹 imgs。如果资源或路径添加不对,会编译报错。

对于 resources 属性,有两个静态方法:process()copy()

  • copy() 会直接拷贝,保存目录结构,可直接 copy 文件夹。
  • process() 是推荐的方式,它所配置的文件会根据具体使用的平台和内置规则进行适当的优化,但只能针对单个文件,而不能处理整个文件夹下的资源。

使用示例:

public func bgImg() -> some View {
    let path = Bundle.module.path(forResource: "imgs/wechat@2x.png", ofType: nil)
    guard let uiimage = UIImage.init(contentsOfFile: path!) else {
        fatalError("image load path error: \(path as Any)")
    }
    let img = Image(uiImage: uiimage)
    return self.background(img)
}

推荐使用默认文件夹 Resources。在 .target 下添加 resources,使用默认文件夹 Resources,然后在 process 中指定文件夹 Resources。使用的时候无需引用该路径,Swift 在编译的时候不会添加 Resources 路径。

public func bgImgUrl() -> some View {
    let path = Bundle.module.url(forResource: "wechat@2x", withExtension: "png")
    guard let data = try? Data(contentsOf: path!),
          let uiimage = UIImage.init(data: data) else {
        fatalError("image load path error: \(path as Any)")
    }
    let img = Image(uiImage: uiimage)
    return self.background(img)
}

Assets.xcassets 中添加的图片资源不需要使用路径方式,使用方式如下:

Image("imageName", bundle: .module)

SPM 不支持混合语言开发,在同一个 target 中无法使用多语言,否则编译报错。

如何实现混合语言

可参考相关文章。这里是一个 Swift 和 OC 混编的示例:每种语言一个 target,单个 target 内不可使用多语言。对外导出的 .h 头文件,默认放在 include 文件中。如果要自定义导出文件,需要设置 publicHeadersPath 导出的公共头文件夹路径。例如,把原来的 include 文件名改为 header,然后把这个 OC 的包添加依赖到需要使用的 Swift 的包里,就可以正常使用了。

0 Answers