将Objective-c框架导入Swift框架(Google Analytics + Cocoapod)

13
我想将我常用的Swift代码集中到一个框架中,其中一部分代码使用了Google Analytics。我通过Cocoapod引入了Google Analytics,但是从新的框架中无法像在原始项目中那样访问它,因为它是Objective-C,并且在框架中没有桥接头文件的支持[我使用的是Swift 1.2]。
我通常在桥接头文件中有一行代码可以使所有这些工作正常运行:
#import 我应该把它放在项目的哪个位置才能使它像以前在桥接头文件中那样正常工作?
我在Apple关于混合Swift和Objective-C的文档中发现了这个:
如果你正在编写混合语言框架,可能需要从 Swift 访问你的 Objective-C 代码,也需要从 Objective-C 访问你的 Swift 代码。
将一组 Objective-C 文件导入到与 Swift 代码相同的框架目标中,你需要将这些文件导入到该框架的 Objective-C umbrella header 中。要从同一框架中的 Objective-C 代码导入到 Swift,请确保 Packaging 中的 Build Settings 中,该框架目标的 Defines Module 设置为 Yes。在你的 umbrella header 文件中,导入每个你希望暴露给 Swift 的 Objective-C header 文件。例如:OBJECTIVE-C import <XYZ/XYZCustomCell.h>

import <XYZ/XYZCustomView.h>

import <XYZ/XYZCustomViewController.h>。我认为最相关的短语是“you’ll need to import those files into the Objective-C umbrella header for the framework”。

但这个文件是什么,如何创建它?

苹果的文档中提到了早期的内容(在一个表格中):

Objective-C 代码

导入 Swift

#import "Header.h"

好吧,我试着创建一个名为“Header.h”的文件并导入它,但那行不通。我不知道他们想说什么。我在构建设置中找不到任何“伞形”东西。

所以我的问题是,我该如何在我的 Swift 项目中导入这个文件(#import <Google/Analytics.h>),以便它可以像在正常项目的桥接头文件中那样查看 Google Analytics cocoapod 框架?

更新:

我现在认为,也许 Objective-C 的桥接头文件就是与项目同名的 .h 文件。我已经尝试在那里添加导入语句,但出现的错误是:

!在框架模块“JBS”内包含非模块化标头


1
我也在这个问题上苦苦挣扎 - 你最终解决了吗? - Geoffrey Wiseman
还没有。因为这个问题,我一直在避免使用Cocoapods,但是由于这个原因,我目前在技术上正在使用较旧的Google Analytics实现。我期望苹果公司会在某个时候意识到这个问题并采取措施解决它。除非已经有方法可以解决它而我不知道。 - John Bushnell
@John,你能解决“在框架模块中包含非模块化头文件”的问题吗?我正在尝试做同样的事情(通过伞形头文件将GoogleAnalytics cocoapod框架导入到Swift框架中),但是我也遇到了相同的错误。 - nebs
@nebs 我相信是这样的。至少有进展了。请看我的回答以获取解释。 - John Bushnell
3个回答

5
对于那些一直在问我是否解决了这个问题的人,以下是我将KochavaTracker SDK Cocoapod导入框架的方法。该SDK目前是用Objective-C编写的。这个答案基于nuKs提供的答案,并有以下具体步骤。
1)在你的项目文件夹下创建一个名为KochavaTracker的文件夹,即MyFramework/MyFramework/KochavaTracker。
2)在该文件夹中创建一个名为module.modulemap的文件,并插入以下内容:
/*
 This is the private module which is used to make private ObjC headers available to Swift code.
 Note how all header files need to be specified with paths relative to this file.

 This file lives inside a folder, and that folder is the actual module. In Xcode the SWIFT_INCLUDE_PATHS needs to include the parent directory to that folder.
 */
module KochavaTracker {
    header "../../Pods/KochavaTrackeriOS/KochavaTrackeriOS/Classes/KochavaTracker.h"
    export *
}

这个步骤实际上创建了一个模块,作为SDK接口的包装器,Swift之后可以像导入其他Swift模块一样导入它。请注意,它依赖于相对路径到Pods文件夹。
3) 如构建设置中发现,请修改SWIFT_INCLUDE_PATHS以包括:
$(SRCROOT)/KochavaTracker

这样做可以使你能够导入该模块,并定位到你在其下创建的KochavaTracker文件夹。

4)根据需要在你的Swift代码中添加:

import KochavaTracker

从那里,您应该能够引用KochavaTracker模块中的类。


$(SRCROOT)/MyFramework should be $(SRCROOT)/KochavaTracker - Wyetro
已编辑。感谢 @Wyetro - John Bushnell
1
如果MyFramework也是由CocoaPods管理的,我应该在规范文件中编辑一些内容,而不是修改SWIFT_INCLUDE_PATHS为$(SRCROOT)/KochavaTracker吗? - boog

4
解决方案并不像应用程序那样简单。我们需要创建一个模块映射。
请查看此示例存储库
在Swift代码中,我们只能导入所谓的模块。诀窍是定义一个模块,该模块又包含了所有我们需要Swift代码访问的ObjC头文件。 本文的模块映射部分也可能对您有所帮助。
虽然桥接头很方便,但它有一个关键限制——你不能在框架项目中使用它。另一种选择是使用模块。
要实现这一点,请在项目目录中创建一个以要使用的库命名的目录。我在shell中进行了此操作,命名为CommonCrypto。在目录内部,创建一个module.map文件,封装库设置。对于CommonCrypto,module.map如下所示: module CommonCrypto [system] { header "/usr/include/CommonCrypto/CommonCrypto.h" export * } 现在,在Swift Compiler - 搜索路径下的Import Paths中添加新模块。在模块路径中使用${SRCROOT}(例如${SRCROOT}/CommonCrypto)可确保项目无论在何处检出都能正常工作。
这使得您可以在Swift文件中直接导入CommonCrypto。请注意,使用此技术构建的任何框架的消费者也必须将该模块添加到其Swift搜索路径中。
我按照上面文章中的步骤,并以以下方式满足我的需求: module Muse { header "Muse.framework/Headers/Muse.h" export * } 我为了安全起见(因为它会删除警告),移除了[system] lexon,并将框架放在与module.map文件相同的文件夹中。
另外,如果需要,请不要忘记在您的框架目标(在常规选项卡的链接的框架和库部分)中包含libc++.tbd和其他必需的依赖项。

它说:“使用此技术构建的任何框架的消费者也必须将模块添加到其Swift搜索路径中。”但是,如果我将我的框架作为二进制文件而不是源代码进行发布,我的用户如何将模块添加到其搜索路径中? - cha77a

-2

桥接头文件是一种特定的头文件,用于将Objective-C文件转换为Swift框架。

您可以在Apple doc中了解更多关于桥接的内容:

Xcode会随着您创建的文件一起创建头文件,并将其命名为您的产品模块名称,后面加上“-Bridging-Header.h”。 (稍后您将在命名产品模块时了解更多信息。)

因此,您唯一需要做的就是手动创建该文件,方法是选择

文件 > 新建 > 文件 > (iOS、watchOS、tvOS或OS X) > 源代码 > 头文件。

如果您的框架名称为ABC,则头文件的名称应为:

例如:ABC-Bridging-Header.h

您可以将其放在框架项目中任何位置。

希望这能帮助到某些人!


尝试在框架中执行此操作会生成以下错误:"<unknown>:0: error: using bridging headers with framework targets is unsupported." - John Bushnell
我不明白这个问题。我的框架内有一个目标,但除此之外,你指的是什么? - John Bushnell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接