【问题标题】:How to import private framework headers in a Swift framework?如何在 Swift 框架中导入私有框架头文件?
【发布时间】:2015-04-29 01:14:59
【问题描述】:

我有一个 Objective-C 框架(框架 A),它公开了一些公共和一些私有标头。公共标头也在框架的总括标头中声明。我有第二个与 Objective-C 框架链接的 Swift 框架(框架 B)。

现在,如果我想在 B 中导入 A 的公共标头,我只需要做一个 import A

但是我该如何导入私有标头呢?

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

【问题讨论】:

    标签: ios objective-c swift clang


    【解决方案1】:

    你需要修改框架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目标的“构建设置”中,搜索“Private Module Map File”行,然后:

      $(SRCROOT)/A/private.modulemap
      
    3. 不要在“编译源”中包含private.modulemap 文件。这会导致不必要的警告。

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

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

      import A
      import A.Private
      

    【讨论】:

    • 这可行,但是如果私有标头之一需要导入公共标头会怎样?就我而言,我收到“找不到标题”错误。在编译私有子模块时,编译器似乎不知道公共模块。
    • 在我的环境中,它可以正常工作。查看此项目文件:dropbox.com/s/srmgbktyhtmtuku/PrivateFWTest.zip?dl=0
    • 原来是因为我的库位于它自己的 Xcode 项目中,该项目用作外部项目。单独编译库是可行的。在您的示例中将库创建为同一项目中的目标也可以。
    • 我如何在框架内使用私有模块?
    • @KoCMoHaBTa 即使在模块A 内,你也可以import A.Private
    【解决方案2】:

    这个问题发布已经有一段时间了。接受的答案非常好,就我而言,这是一种常见的方法。

    问题是,它并不是真正的“私人”。您可以在框架内执行此操作以访问“私有”部分:

    // Framework A Swift file
    import A.Private
    

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

    // Client App Swift file
    import A
    import A.Private
    
    // access "private" framework methods and classes
    

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

    我找到了解决该问题的方法,但有点过于复杂,无法将其作为一个整体粘贴到此处。

    我在没有媒体的情况下发表了一篇关于它的帖子。也许它会帮助某人检查这个问题,这是我文章的链接:

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

    【讨论】:

    【解决方案3】:

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

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

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

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

    【讨论】:

      【解决方案4】:

      我的情况可能与我的设置有关,但我会在这里提供,以防它帮助其他人。我还有一个带有私有标头的 Objective-C 框架(框架 A),我需要在链接它的 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 就无法使用位于 FrameworkA 中的私有模块映射中的路径找到私有标头。对我有用的是在私有模块映射中使用PrivateHeaders 目录的相对路径:

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

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

      【讨论】:

      • 我在使用 pod 设置的私有模块映射时遇到了同样的问题。我记得在规范中有 module_map 设置,但我最终决定换一种方式(如果您仍然感兴趣,请在此处发布答案)
      猜你喜欢
      • 1970-01-01
      • 2011-05-11
      • 2011-05-11
      • 2019-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-01
      • 2015-05-19
      相关资源
      最近更新 更多