如何在 Swift 框架中导入私有框架 headers?

How to import private framework headers in a Swift framework?

我有一个 Objective-C 框架(框架 A)公开了一些 public 和一些私有 header。 public header 也在框架的保护伞 header 中声明。我有第二个 Swift 框架(框架 B)与 Objective-C 框架链接。

现在,如果我想在 B 中导入 A 的 public header,我只需要执行 import A.

但是我该如何导入私有 headers?

我知道桥接 header 不是一个选项,因为框架不支持它。我是否需要以某种方式为私人 header 创建一个单独的保护伞 header?

您需要修改框架A,使其导出私有模块。

  1. A 项目中创建一个 private module map file。这将是这样的:

    A/private.modulemap:

    explicit module A.Private {
    
        // Here is the list of your private headers.
        header "Private1.h"
        header "Private2.h"
    
        export *
    }
    
  2. 在框架 A 目标的 "Build Settings" 中,搜索 "Private Module Map File" 行,并使其成为:

    $(SRCROOT)/A/private.modulemap
    
  3. 不要在 "Compile Sources" 中包含 private.modulemap 文件。这会导致不必要的警告。

  4. 清理并构建框架 A 目标。

  5. 在框架 B Swift 文件中。您可以像这样导入私有模块:

    import A
    import A.Private
    

我的情况可能与我的设置有关,但我会在此处提供,以防对其他人有所帮助。我还有一个 Objective-C 框架(框架 A)和私有 headers,我需要在链接它的 Swift 框架(框架 B)中使用它。一些额外的细节:

  1. 每个框架在工作区中的一个单独项目中

  2. 项目使用CocoaPods

  3. podspec定义了两个框架之间的依赖关系:

    s.subspec 'FrameworkA' do |cs|
        cs.vendored_frameworks = "lib/FrameworkA.framework"
    end
    
    s.subspec 'FrameworkB' do |ts|
        ts.dependency 'FrameworkA'
        ts.vendored_frameworks = "lib/FrameworkB.framework"
    end
    

@rintaro 提供的解决方案在 Xcode 中 运行 时对我来说非常有用,但是一旦部署了 Pod,FrameworkB 就无法找到私有 headers 使用位于 FrameworkA 中的私有模块映射中的路径。对我有用的是在私有模块映射中使用 PrivateHeaders 目录的相对路径:

module FrameworkA_Private {
    header "../FrameworkA.framework/PrivateHeaders/Private.h"
    export *
}

这适用于 Xcode 使用 CocoaPods 安装的最终产品。这有点 hacky,因为它引用了最终构建产品中的一个文件夹,如果有其他方法告诉 CocoaPods 如何保留这些路径,我不会感到惊讶,但不管它是什么,我都没有找到它。这暂时解决了问题。

这个问题 post 已经有一段时间了。接受的答案非常好,就我而言,这是一种普遍的做法。

问题是,它不是真的"private"。您可以在您的框架内执行此操作以访问 "private" 部分:

// Framework A Swift file
import A.Private

但是如果你在应用中使用框架A(或者你将它发送给你的客户),他仍然可以做到:

// Client App Swift file
import A
import A.Private

// access "private" framework methods and classes

我试图解决这个问题,因为我最近遇到了一种情况,我需要对用户隐藏它(闭源框架)——我只是不能让任何人访问它,因为它对 SDK 的完整性构成威胁。

我找到了解决该问题的方法,但有点太复杂,无法将其作为一个整体粘贴在这里。

我做了一个post关于它的无媒介。也许它会帮助某人检查那个问题,那是我文章的 link:

https://medium.com/@amichnia_31596/creating-swift-framework-with-private-objective-c-members-the-good-the-bad-and-the-ugly-4d726386644b

正如 Andrzej Michnia 在他的回答中所指出的,“私有模块映射”解决方案的问题在于它并不是真正完全私有的,并且那些“私有”headers 仍然可以被其他人看到,因为它们是仍然包含在我们的框架中。如果有人打开带有这种“私有”模块的编译框架,他仍然会看到您隐藏的所有 .h 文件。

如果我们需要在我们的 swift 框架中对其他用户完全隐藏一些 objective-c header,那么另一种可能的方法就是让它们 public 并在手动或使用 bash 脚本构建框架后将它们从我们的框架中删除。

您可以创建一个单独的 header 文件,例如“InternalHeaders.h”,您可以在其中导入您不想公开的所有 header。然后将此 InternalHeaders.h 导入框架的 public 伞 header 中。使所有 headers public 以便您可以编译所有内容。构建框架后,只需从 public 保护伞 header 中删除“导入 InternalHeaders.h”,然后删除所有您不想手动或使用 [=23] 公开的 header =] 脚本或 运行 脚本构建阶段,仅此而已。

仍然不是一个完美的解决方案,但在某些情况下,在 swift 中编写协议以匹配其他答案中提出的每个 objective-c 接口可能会更容易和更快。