在闭源 Swift 框架中嵌入框架

Posted

技术标签:

【中文标题】在闭源 Swift 框架中嵌入框架【英文标题】:Embedding frameworks inside closed-source Swift framework 【发布时间】:2015-11-19 05:39:59 【问题描述】:

我们公司希望向我们的客户分发适用于 ios 的闭源 SDK。我一直在使用 Cocoapods 构建框架并使用它构建了一个示例应用程序。以前,该应用程序在模拟器上以及在设备上部署时都可以正常工作。但是,我还在应用程序本身中嵌入了 Pods.framework 文件。可能感兴趣的另一条信息是该框架是用 Swift 编写的,包含的 cocoapods 依赖项既是 Swift 又是 Objective-C。

我想让 pod 需求更易于管理,这样用户就不需要关心它们,并尝试将 Pods.framework 文件嵌入到我们正在构建的 SDK 中 - 所以我删除了以下步骤 Embed Pods Frameworks 和 Copy Pods Resources 从示例应用程序中,仅将它们保留在框架中,我还删除了 Pods.framework 作为示例应用程序的依赖项,仅将其保留在开发工具包。这似乎在模拟器中工作,但应用程序现在在移动设备上崩溃并出现 dyld: Library not loaded 错误。

在研究它时,我偶然发现了一些相关的讨论: https://github.com/CocoaPods/CocoaPods/issues/344https://objectpartners.com/2014/06/25/developing-private-in-house-libraries-with-cocoapods/

但是,使用私有 pod 的建议解决方案似乎不适合我们,据我了解,私有 pod 中的源代码仍然是开放的,我们无法与客户共享。

有人可以建议在这种情况下可行的解决方案吗?

【问题讨论】:

不久前我遇到了和你一样的问题,因为沮丧而放弃了。其实,差不多是同一时间。不幸的是,我没有找到解决方案。幸运的是我在我的框架开发的早期,所以我把它改成了 Objective-C,所以它可以是闭源的。然后我放弃了 Pods,只将它需要的 1 个框架导入到它的项目中。 我认为您的第一个链接可能不是您想要的。它链接到饼图库。你有没有想过如何做到这一点?有很多关于如何制作私人 cocoapod 的文档,但我找不到关于制作闭源 cocoapod 的文档 - 或者至少没有一个不是非常模糊的。 你是对的,链接似乎无关,我可能错误地链接了一个错误的 CocoaPod 问题,不幸的是我不记得我的意思是原来的那个。我确实弄清楚了这一点,并且可以发布我的解决方案,尽管它很脆弱并且需要一些跳圈。 我遇到了你描述的同样的问题,你能发布你的解决方案吗? 【参考方案1】:

好的,我终于有了一个更持久的解决方案。现在我了解了 Xcode 在我的 Swift 子框架中的链接如何更好地工作,它是我旧版本的修改后、更简洁的版本

使分发/编译有点难看的问题:

由于 Swift 标准库没有像 Obj-C 那样捆绑在设备上,也不能保证它们在版本之间是稳定的(Swift 3 中承诺的稳定二进制接口:https://github.com/apple/swift-evolution#development-major-version--swift-30)我们必须确保整个项目是针对同一版本的 Swift 编译的。这意味着使用你的闭源框架的人必须在他们的项目中使用与你编译库时相同版本的 Swift,即使他没有在代码中使用 Swift,因为最终是他的 Swift 版本被捆绑到应用程序中并且您的 SDK 运行。这只是闭源框架的一个问题,因为开源框架将始终针对与最终项目相同的版本进行编译。可能的解决方法是将客户端限制为您使用的相同版本或分发多个编译(即 Swift 2.1 和 Swift 2.0)。为了解决这个问题,您可以向用户提供针对多个 Swift 版本编译的二进制文件的副本。

除此之外,这是我在编译/分发期间必须做的事情,以制作一个在 Swift 中工作的二进制框架:

构建框架时:

在项目目标中,确保将 Pods.framework 添加到 Linked Frameworks and Libraries(确保这是 Pods.framework 的预编译 RED 版本,我在同一目录中有一个黑色编译的 Pods.framework,它构建得很好,但随后产生的框架会导致项目在后续项目的链接器阶段抱怨缺少 armv7 架构) 在 Build Settings 的 User-Defined 部分下,添加一个名为 BITCODE_GENERATION_MODE 的字段并将其设置为 bitcode 不要 #import 桥接头中的任何框架,所有告诉你这样做的指令都是 Swift 1.0-1.2 天遗留下来的,你不再需要它,它弊大于利(以后的项目将抱怨它找不到这些甚至没有暴露给它的标头) 将构建目标更改为 Generic iOS DeviceArchiveExport 框架

使用框架构建项目时:

将框架拖放到项目中,在 General 选项卡中将其添加到 Embedded BinariesLinked Frameworks and Libraries(您只需添加框架本身,无需子框架或 pods 文件) 在“构建设置”选项卡中,将新路径添加到 Framework Search Paths$(PROJECT_DIR)/MyFramework.framework/Frameworks 构建项目

【讨论】:

我不明白这如何解决您的快速版本控制问题。如果您的客户使用的是 swift 2.3 并且您的框架是针对 3.0 编译的,会发生什么? 在同一段中,紧随其后的两句话解释了两种可能的解决方法。除此之外,在 Swift 停止拖延标准化他们的 ABI 之前,没有好的解决方案。 @AlexanderTsepkov 您可以为每个 Swift 版本分发一个编译框架。这可以自动化。 @Demi 与我的第二个解决方法(“分发多个编译(即 Swift 2.1 和 Swift 2.0)”)不同吗? @AlexanderTsepkov 是的。我只是指出这可以 100% 自动化,并且不需要太多的重复工作。

以上是关于在闭源 Swift 框架中嵌入框架的主要内容,如果未能解决你的问题,请参考以下文章

无法调试嵌入在 Objective-C 应用程序中的 Swift 模块/框架

在构建带有关联 Swift 库的 Swift 命令行工具时,为啥要嵌入框架?

避免子框架嵌入iOS

Xcode:“没有这样的模块”嵌入式框架

如何将 Vuforia Unity 2017.3 构建 OC iOS 项目作为框架嵌入/集成到 Swift iOS 项目中

带有嵌入库的 Cocoa Touch Framework Swift