Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
231 views
in Technique[技术] by (71.8m points)

ios - Detect and use optional external C library at runtime in Objective-C

I am building an SDK that iPhone developers can include in their projects. It is delivered as a compiled ".a", without source code. Let's call my SDK "AAA".

The customer in his project (let's call it "BBB"), in addition to use AAA, may also use a 3rd party library called "CCC" - which also comes pre-compiled, closed-source. I do not sell CCC, it's a different company.

My SDK, AAA, can optionally use CCC to improve the product, using those 3rd party features. For example, let's say CCC is a security SDK to encrypt something. AAA does not require CCC, but will be more secured if the customer chooses to include CCC in their project as well.

Now here is an extra tricky part - the CCC library, is pure C code, made of C Structs and C functions - nothing object-oriented about it.

The issues are:

  • How can I compile my AAA SDK to use functions/structs from CCC, without including CCC in my project (not legally allowed to, and don't want to keep up to date with version updates).
  • How can I detect if the customer has CCC in his project, to use those extra features only if available?
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Use dlsym to get the C function pointers by function name. If it can find them, they're there. Otherwise they're not. Just use RTLD_DEFAULT as the first parameter.

EDIT: having cast around for an iOS example, see Mike Ash's write up of PLWeakCompatibility, particularly the section on 'Falling Through'. You'll see he checks whether objc_loadWeakRetained (a runtime call related to weak references) is present. Under 5+ it is and his version calls the real one directly. Under 4 it isn't so his version does something else instead.

EDIT2: sample code:

Sample 1:

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

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

Outputs 0x0. Sample 2:

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

void someFunc()
{

}

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

Outputs an address other than 0x0.

Sample 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();
    }
}

Outputs Hi!.

Structs have no presence in a .a or elsewhere at runtime, they're just instructions to the compiler on how to format data. So you'll need to include either the actual structs or a compatible restatement of them in your code.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...