将RxSwift作为XCFramework与CocoaPods相结合

897 阅读6分钟

几周前,我试图通过CocoaPods整合RxSwift从第6版开始提供的预编译的XCFrameworks。但是,令我吃惊的是,使用CocoaPods不可能做到。唯一的办法是手动整合它们。

我想出了一个解决这个限制的方法,并认为分享它将是一个好主意。在这里我将一步一步地解释。

让我们开始吧!

首先是小声明

这个变通方法是在以下情况下开发和测试的。

  • RxSwift 6.5.0
  • Xcode 13.2.1
  • CocoaPods 1.11.2

背景。我为什么要关心这个?

我在一个大型的项目上工作。

我们项目的一个主要部分依赖于RxSwift 和他的伙伴(RxCocoa,RxBlocking, 和RxTest )。我们不打算将现有的代码库迁移到Combineasync/await

我们使用CocoaPods作为一个依赖管理器。我们也不打算将其迁移到Swift Package Manager。

我们的项目从头开始构建需要数分钟(例如我们的CI每次都从头开始构建)。为了减少编译时间,我们一直在用一些依赖项提供的XCFrameworks代替 "正常 "的依赖项(你有源代码,需要编译的依赖项)。

从第6版开始,RxSwift对XCFrameworks提供了更好的支持。现在每个新版本都附加了所有需要的XCFrameworks。

所以我们认为把它们集成到我们的项目中是个好主意,可以节省一些编译时间。但不幸的是,在写这篇文章的时候,XCFrameworks没有在CocoaPods下发布。

但这并不能阻止我们。

解决办法。构想

我们需要为每个需要的依赖性定制podspec 文件。这些podspecs ,以便从RxSwift的GitHub发布页面上获得出售的框架。

编辑好的podspecs ,可以存储在项目的本地,也可以远程托管在不同的规格库中。

然后,我们需要做的就是在我们的Podfile中使用这些编辑好的podspecs

我们就可以开始了。

如果你不想按部就班,这里有一个资源库,里面有两个使用该解决方法的例子项目。一个项目在本地有修改过的podspecs,另一个使用远程托管的podspecs

只对修改后的podspecs感兴趣?你可以在这里找到它们。

解决方法。一步一步来

我将一步一步地解释这些变化。我将在例子中只使用RxSwift 6.5.0 ,以使事情简单。但同样的改变也适用于所有其他的Rx框架和任何其他版本。

对podspec文件的修改

我们需要对RxSwift.podspec 文件做一些修改。你可以在这里找到原始文件。这些改动是。

  • 改变s.version 。为了避免混淆,我们需要改变依赖关系的版本。由于我想使用6.5.0版本的XCFramework,那么我把版本改为6.5.0-xcframework
  • 改变s.source 。它需要指向包含XCFramework的zip文件。在这种情况下,源码被改成{ :http => "https://github.com/ReactiveX/RxSwift/releases/download/6.5.0/RxSwift..xcframework.zip" }
  • 删除s.source_filess.exclude_files 。我们不需要它们。
  • 添加带有值的s.vendored_frameworks "RxSwift.xcframework"

你可以在这里找到完整的编辑过的文件。

对Podfile的修改

最后一步是修改项目的Podfile。在这里你要做一个选择。

**A.**如果你选择在本地存储podspecs ,那么你必须改变你的依赖声明,使用本地的podspec 。你可以通过:podspec 参数来完成这个任务。例如,如果你的自定义podspecs 是存储在一个名为RxSwiftSpecs 的文件夹内,那么改变就会是。

pod 'RxSwift', :podspec => './RxSwiftSpecs/RxSwift.podspec'

你可以在这里看到一个使用这种方法的项目。检查Podfile和本地podspecs在 [RxSwiftSpecs](https://github.com/pmanuelli/RxSwiftXCFrameworkCocoapodsExample/tree/main/LocalPodspecsExample/RxSwiftSpecs) 文件夹

**B.**如果你选择将你的规格存储在远程规格库中,那么首先你需要将规格库的URL添加到Podfile中,如。

source 'https://github.com/pmanuelli/RxSwiftSpecs.git'

然后指定你在podspec上设置的版本。

pod 'RxSwift', '6.5.0-xcframework'

你可以在这里看到一个使用这种方法的项目。在这种情况下,请在这里检查Podfile和远程规格库。

一个特殊的案例。RxCocoa

RxSwift,RxRelay,RxBlocking, 和RxTest 的修改是非常简单的。

但是,RxCocoa 则更具挑战性。

RxCocoa

正如RxSwift的XCFramework安装指南中所说,如果你想导入RxCocoa ,那么你也需要导入RxCocoaRuntime 。但当我检查原始的 RxCocoa.podspec 文件时,我发现RxCocoaRuntime 没有被设置为依赖关系。这让我很吃惊。

因此,考虑到没有RxCocoaRuntimeRxCocoa 就不能工作,对podspec 的一个额外的修改就是添加这个依赖关系。

s.dependency 'RxCocoaRuntime', '6.5.0-xcframework'

最后的RxCocoa.podspec 文件在这里

现在剩下的就是应用RxCocoaRuntime.podspec 的修改。

RxCocoaRuntime

但是RxSwift上没有RxCocoaRuntime.podspec 。我想既然它不是在CocoaPods下发布的,那就没有理由要有。

但这个解决方法需要一个。

我检查了SPM清单文件中的RxCocoaRuntime依赖关系,我发现它只依赖RxSwift。所以,知道了它的依赖关系,创建podspec 就很容易了。

最后的RxCocoaRuntime.podspec 文件在这里

关于这个框架的一个细节是,它没有6.5.0 。在写这篇文章的时候,最新的版本是 _6.2.0_.我想,如果框架没有变化,那么就不会有新的版本产生。这是有道理的,但对我来说是不幸的,因为我更喜欢为我所有的Rx依赖性提供相同的版本。

如果你愿意,完全可以创建一个6.2.0-framework 版本。

但我更喜欢把它命名为 _6.5.0-framework_尽管它使用的是预编译的 _6.2.0_版本。这样,在Podfile中,我所有的Rx依赖都有相同的版本。

我们完成了!

应用所有提到的修改后,唯一要做的就是运行pod install ,看到XCFrameworks出现在项目上。

所有我们必须在左边编译的代码现在都被右边的一些漂亮的XCFrameworks所取代。

版本更新怎么办?

这个解决方案的一个缺点是,现在的版本更新过程比 "正常 "的依赖关系更复杂。

首先,你需要为更新的版本创建新的podspecs 。你应该改变podspec 上的版本号,并改变zip的路径,指向新版本。

下一步取决于你在哪里存储podspecs

如果你在本地存储它们,你可以直接覆盖以前的podspecs 。但如果你把它们存放在一个远程规格库中,你需要先把它们添加到库中,然后更新你的Podfile上的版本号。

最后,运行pod update ,你就完成了。

总结

我不得不承认,这比我最初预期的要多一点额外的工作。但我对最后的结果相当满意。我们最终成功地使用了XCFrameworks,通过CocoaPods集成了它们

这样我们就避免了反复编译这些依赖项(例如在我们的CI上),节省了一些宝贵的时间。但它的代价是一个更复杂的解决方案和一个稍微困难的版本更新过程。

对我来说,这个代价完全值得

再次,这里是使用这种解决方法的例子项目,有两种方法来存储podspecs。

如果你只想要6.5.0版本的修改后的podspec文件,你可以在这里找到它们。

GitHub - pmanuelli/RxSwiftXCFrameworkCocoapodsExample。示例项目,演示如何使用...