在Objective-C中运行时检测并使用可选的外部C库

Nat*_*n H 12 c objective-c late-binding static-libraries ios

我正在构建一个iPhone开发人员可以在他们的项目中包含的SDK.它以编译的".a"形式提供,没有源代码.我们称我的SDK为"AAA".

除了使用AAA之外,他的项目中的客户(我们称之为"BBB")也可以使用名为"CCC"的第三方库 - 它也是预编译的,闭源的.我不卖CCC,这是一家不同的公司.

我的SDK,AAA,可以选择使用CCC来改进产品,使用这些第三方功能.例如,假设CCC是用于加密某些内容的安全SDK.AAA不需要CCC,但如果客户选择在其项目中包含CCC,则会更安全.

现在这里有一个特别棘手的部分 - CCC库,是纯C代码,由C Structs和C函数组成 - 没有任何面向对象的东西.

问题是:

  • 如何编译我的AAA SDK以使用来自CCC的函数/结构,而不在我的项目中包含CCC(不合法允许,并且不想跟上版本更新).
  • 如何检测客户是否在其项目中具有CCC,仅在可用时使用这些额外功能?

Tom*_*mmy 8

用于dlsym按函数名称获取C函数指针.如果它能找到它们,它们就在那里.否则他们不是.只需RTLD_DEFAULT用作第一个参数.

编辑:为了一个iOS示例,请参阅Mike Ash 撰写的PLWeakCompatibility,特别是关于"Falling Through"的部分.您将看到他检查是否存在objc_loadWeakRetained(与弱引用相关的运行时调用).在5+以下它是和他的版本直接称为真实的.在4以下并不是他的版本做了别的事.

EDIT2:示例代码:

样本1:

#import <Foundation/Foundation.h>
#include <dlfcn.h>

int main(int argc, char *argv[]) 
{
    @autoreleasepool
    {
        NSLog(@"%p", dlsym(RTLD_DEFAULT, "someFunc"));
    }
}
Run Code Online (Sandbox Code Playgroud)

输出0x0.样本2:

#import <Foundation/Foundation.h>
#include <dlfcn.h>

void someFunc()
{

}

int main(int argc, char *argv[])
{
    @autoreleasepool
    {
        NSLog(@"%p", dlsym(RTLD_DEFAULT, "someFunc"));
    }
}
Run Code Online (Sandbox Code Playgroud)

输出0x0以外的地址.

样本3:

#import <Foundation/Foundation.h>
#include <dlfcn.h>

void someFunc()
{
    NSLog(@"Hi!");
}

int main(int argc, char *argv[])
{
    @autoreleasepool
    {
        void (* func)();
        func = dlsym(RTLD_DEFAULT, "someFunc");
        func();
    }
}
Run Code Online (Sandbox Code Playgroud)

输出Hi!.

结构在运行时没有存在于.a或其他位置,它们只是指示编译器如何格式化数据.因此,您需要在代码中包含实际结构或其中的兼容重述.