如何创建一个 Library/Framework ,只有在编译时存在时才会被链接和使用

How to create a Library/Framework that will be linked and used only if present at compile time

我有兴趣复制您在 Apple 框架中看到的那种功能:应用程序可以利用更新版本 iOS 上的新框架,但在缺少它们时不会失败.

当然,如果有另一种解决问题的方法,我很乐意看到它。


我所在的位置如下:

公司 A 向第三方提供 iOS 框架(以下称为 FrameA),他们可以 link 进入他们的应用程序。

我的任务是创建一个可选模块,该模块可以 "bolted on" 到 FrameA,但实际上并不是它的一部分(这是因为 FrameA 经常针对不同的客户和其他业务进行更新和定制限制)。

第三方可以选择是否使用附加库(或框架,或任何可以工作的)。如果它存在,FrameA 必须 link 它并且代码执行它的功能。如果它不存在,那么 FrameA 会像现在一样继续。它必须适用于接收新版本 FrameA 而不是附加库的第三方。 我应该尽可能少地对 FrameA 进行更改,因为这些更改必须由另一个团队继续维护。

我还需要在 Apple 的提交规则中执行此操作,解决方案必须至少支持 iOS6、7 和 8。因此不允许动态 linking。 A公司直接向第三方提供FrameA,所以Apple唯一需要认可的部分就是最终的App。

这种事情我小范围做过,还不错

在 FrameA 中,使用工厂实例化所有 bolt-on objects。工厂使用 NSClassFromString() 动态获取 class。避免 class 方法:这会让事情变得更难。尽可能使用协议而不是 classes:这使事情变得更容易。

- (id<FABoltOnProtocol>)createBoltOnClass
{
    return [[NSClassFromString(@"BOBoltOnClass") alloc] init];
}

此代码将 运行 即使 BOBoltOnClass 未链接到最终应用程序。 NSClassFromString(@"BOBoltOnClass") 将 return Nil[Nil alloc] returns nil[nil init] returns nil.

您可以用同样的方法测试 bolt-on 是否存在。

BOOL MyHasBoltOn
{
    return NSClassFromString(@"BOBoltOnClass") != Nil;
}

缺点是必须使用 bolt-on 中的 headers 编译 FrameA。这就是我推荐协议的原因。这些协议可以由 FrameA 拥有并且 bolt-on 将遵守它(注意:我通过使用 FrameA 的前缀 FA 和 class 与 bolt-on 的前缀 BO 命名协议来暗示这一点) .

最后,作为一个字符串,您可以从配置文件中读取@"BOBoltOnClass",这样您就可以根据需要交换不同的bolt-on。

请注意必须设置构建标志 -ObjC,否则编译器将不会加载 bolt-on classes 的符号,因为它们不是常规调用的.