如何将C库集成到Swift中编写的iOS应用中

如今,每个人都重视隐私和安全性。 这就是为什么最近我们需要在我们的Distillery项目之一上使用加密库的原因。

对于相关项目,已决定使用libsignal 。 libsignal最初是为Signal Private Messenger开发的,在安全专家中享有很高的声誉。

使用libsignal

在2018年7月末,在Pure CJavaJavaScript中实现了libsignal。 在Objective-C中也有一个称为SignalProtocolKit的实现 ,但那时它已被弃用。

我们的目标是在以Swift编写的iOS应用程序中使用该库。 为了使所有内容保持最新,我们必须使用C语言编写的代码,源代码存储在此处。 幸运的是, Swift可以非常顺畅地与C代码交互,至少因为苹果的一些底层库是用C编写的。 棘手的部分是将库正确添加到项目中。

创建一个module.map

经过一些研究,我发现我可以简单地将库的源代码添加到项目中,并创建一个module.map文件来指定要公开的库头(有关更多信息,请查看此博客)。 libsignal包含许多头文件,但是如果我想在常规C项目中使用它,则只需包含一个称为signal_protocol.h的文件。 由于signal_protocol.h包括它依赖的其他头文件,就像其他每个头文件一样,我们可以确定所有文件都包括在内。 因此,我制作了一个具有以下内容的module.map文件:

module SignalProtocol [system] { 
header “src/signal_protocol.h”
export *
}

然后,将其放入带有库源代码的文件夹中,将其添加到项目中,然后开始进行测试。

Xcode允许导入此模块并使用某些库函数,但是缺少某些库组件。 例如,我无法使用signal_protocol_internal.h中定义的signal_context数据类型。

在那一刻,很明显Xcode没有正确包含嵌套的头文件。 因此,我决定尝试将来自libsignal的所有标头包含在我的module.map文件中。 (将更新后的module.map放在这里是多余的,因为它只包含与上面的文件类似的每个* .h文件。)

完成此操作并尝试构建以构建项目后,我从libsignal中获得了许多与某些头文件有关的错误。 当我查看它们时,我意识到有些头文件不是实际的头文件。 相反,它们存储一些常数值,并按如下方式使用:

 static const fe sqrtm1 = { 
#include “sqrtm1.h”
} ;

截至2018年7月底,已使用以下文件:

 sqrtm1.h 
ge_sub.h
pow225521.h
ge_add.h
d2.h
ge_madd.h
ge_msub.h
pow22523.h
ge_p2_dbl.h
dh
base2.h
base.h

最后,在从module.map中排除这些文件之后,我能够构建项目并使用libsignal的所有部分。

是胜利吗? 我猜是适中的。 将第三方库的源代码直接添加到项目中似乎不太正确,因此我们决定将libsignal包装在Cocoa Touch Framework中

将其包装在Cocoa Touch框架中

首先,在经历了之前的所有困难之后,我认为这部分会很容易。 不幸的是,事实证明我打开刚创建的项目框架的“构建设置”的确切时间,并且找不到“快速编译器-搜索路径”部分。

随后进行了几次尝试,将libsignal源包括在框架中。 我只会描述一个成功的案例。

要将С库包装在Cocoa Touch Framework中 (使用libsignal的示例),请按照以下步骤操作:

1.创建一个新项目。

创建一个新项目。 对于其类型,选择“ Cocoa Touch Framework。

2.添加源文件。

将库的源文件添加到项目中。

3.选择要公开的标题。

转到项目文件,然后选择您的目标框架。 打开“构建阶段”标签。 在此处的“标题”部分中,应显示库中的所有标题。 通过将哪些内容拖到“公开”列表中来确定要公开的内容。 对于libsignal ,我决定将所有标头公开。

顺便说一句,这里您应该拥有所有* .h文件,即使是仅存储常量的文件也是如此。

4.导入标题。

现在,由于所有标头都已添加到您的项目中,因此您必须将它们导入到框架的主标头中,该主标头应称为[您的框架名] .h,并放置在框架的根目录中。 为每个实际的标头添加以下行,省略那些仅存储常量的标头:

 #import “protocol.h” 

请注意,由于我们将所有标头添加到了项目文件中,因此我们仅需使用filename而不指定项目中文件的完整路径。 之所以这样工作,是因为所有标头都在框架捆绑包内复制,并且项目内的所有路径均无效。

瞧! 您应该有一个功能全面的框架。

不过请注意,目前,它有一个主要缺点:它保留了特定版本的libsignal ,并且不允许您从其GitHub存储库中对其进行更新。 但是,该问题不在本文讨论范围之内。

想更多地了解Distillery的开发人员如何创建创新技术解决方案来推动我们的项目前进? 请查看我们的其他博客-例如 关于优化UIScrollView的 博客 关于使用Travis进行持续集成的 博客 -或 让我们知道!

关于作者

iOS开发人员Artem Garmash于2017年加入Distillery。在业余时间,他喜欢从事硬件项目,要么修改现有设备,要么从头开始构建新硬件。 他还喜欢骑山地自行车,在雪地里散步以及听很多音乐。