在 App 运行时通过 dlopen 和 dlsym 链接加载 bundle 里的动态库。

2018/7/5 posted in  iOS

我们一般引入某个 framework 可能是直接使用#import <AVFoundation/AVFoundation.h>其实还有另一种办法就是使用函数啊 dlopen

函数定义: 
  void * dlopen( const char * pathname, int mode ); 
  函数描述: 
  在dlopen的()函数以指定模式打开指定的动态连接库文件,并返回一个句柄给调用进程。使用dlclose()来卸载打开的库。 
  mode:分为这两种 
  RTLD_LAZY 暂缓决定,等有需要时再解出符号 
  RTLD_NOW 立即决定,返回前解除所有未决定的符号。 
  RTLD_LOCAL 
  RTLD_GLOBAL 允许导出符号 
  RTLD_GROUP 
  RTLD_WORLD 

  返回值: 
  打开错误返回NULL 
  成功,返回库引用 
  编译时候要加入 -ldl (指定dl库) 

dlsym()

 
 功能:

根据动态链接库操作句柄与符号,返回符号对应的地址。
包含头文件:
#include <dlfcn.h>
函数定义:
void*dlsym(void* handle,const char* symbol)
函数描述:
dlsym根据动态链接库操作句柄(handle)与符号(symbol),返回符号对应的地址。使用这个函数不但可以获取函数地址,也可以获取变量地址。
handle是由dlopen打开动态链接库后返回的指针,symbol就是要求获取的函数或全局变量的名称。
dlclose()

 

dlclose用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。
 

示例函数

-(void)mwviewDidLoad{
    //打开动态库
    NSString *path = [[NSBundle mainBundle] pathForResource:@"Kidswaste-Sans Toi" ofType:@"mp3"];
    // 加载库到当前运行程序
    void *lib = dlopen("/System/Library/Frameworks/AVFoundation.framework/AVFoundation", RTLD_LAZY);
    if (lib) {
        // 获取类名称
        Class playerClass = NSClassFromString(@"AVAudioPlayer");
        // 获取函数方法
        SEL selector = NSSelectorFromString(@"initWithData:error:");
        // 调用实例化对象方法
        _runtime_Player = [[playerClass alloc] performSelector:selector withObject:[NSData dataWithContentsOfFile:path] withObject:nil];
        // 获取函数方法
        selector = NSSelectorFromString(@"play");
        // 调用播放方法
        [_runtime_Player performSelector:selector];
        NSLog(@"动态加载播放");
    }
    dlclose(lib);
    NSLog(@"hello world from mwviewDidLoad");
    [self mwviewDidLoad];
    
}