WWDC2014之iOS使用动态库2
2015-06-12 14:44
381 查看
2、通用动态库
经过第一步我们只是创建了一个动态库文件,但是和静态库类似,该动态库并同时不支持真机和模拟器,可以通过以下步骤创建通用动态库:创建Aggregate Target
按下图所示,在动态库工程中添加一个类型为Aggregate的target:
![](http://foggry.com/images/article4/aggregate.png)
按提示一步步操作即可,我给
Aggregate的Target的命名是
CommonDylib。
设置Target Dependencies
按以下路径设置
CommonDylib对应的
Target Dependencies:
1 | TARGETS-->CommonDylib-->Build Phases-->Target Dependencies |
添加Run Script
按以下路径为
CommonDylib添加
Run Script:
1 | TARGETS-->CommonDylib-->Build Phases-->Run Script |
12 | # Sets the target folders and the final framework product. FMK_NAME=${PROJECT_NAME} # Install dir will be the final output to the framework. # The following line create it in the root folder of the current project. INSTALL_DIR=${SRCROOT}/Products/${FMK_NAME}.framework # Working dir will be deleted after the framework creation. WRK_DIR=build DEVICE_DIR=${WRK_DIR}/Release-iphoneos/${FMK_NAME}.framework SIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator/${FMK_NAME}.framework # -configuration ${CONFIGURATION} # Clean and Building both architectures. xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphoneos clean build xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphonesimulator clean build # Cleaning the oldest. if [ -d "${INSTALL_DIR}" ] then rm -rf "${INSTALL_DIR}" fi mkdir -p "${INSTALL_DIR}" cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/" # Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product. lipo -create "${DEVICE_DIR}/${FMK_NAME}" "${SIMULATOR_DIR}/${FMK_NAME}" -output "${INSTALL_DIR}/${FMK_NAME}" rm -r "${WRK_DIR}" open "${INSTALL_DIR}" |
![](http://foggry.com/images/article4/commonlib_setting.png)
该脚本是我根据一篇文章中介绍的脚本改写的,感谢原文作者。
脚本的主要功能是:
1.分别编译生成真机和模拟器使用的framework; 2.使用lipo命令将其合并成一个通用framework; 3.最后将生成的通用framework放置在工程根目录下新建的Products目录下。
如果一切顺利,对
CommonDylibtarget执行run操作以后就能生成一个如图所示的通用framework文件了:
![](http://foggry.com/images/article4/products.png)
使用动态库
添加动态库到工程文件
经过以上步骤的努力,生成了最终需要的framework文件,为了演示动态库的使用,新建了一个名为FrameworkDemo的工程。通过以下方式将刚生成的framework添加到工程中:
1 | Targets-->Build Phases-->Link Binary With Libraries |
1 | Targets-->Build Phases-->Copy Bundle Resources |
![](http://foggry.com/images/article4/framework_demo_setting.png)
仅仅这样做是不够的,还需要为动态库添加链接依赖。
自动链接动态库
添加完动态库后,如果希望动态库在软件启动时自动链接,可以通过以下方式设置动态库依赖路径:1 | Targets-->Build Setting-->Linking-->Runpath Search Paths |
Runpath Search Paths路径依赖设置为main bundle,即沙盒中的FrameworkDemo.app目录,向
Runpath Search Paths中添加下述内容:
1 | @executable_path/ |
![](http://foggry.com/images/article4/run_search_path.png)
其中的
@executable_path/表示可执行文件所在路径,即沙盒中的.app目录,注意不要漏掉最后的
/。
如果你将动态库放到了沙盒中的其他目录,只需要添加对应路径的依赖就可以了。
需要的时候链接动态库
动态库的另一个重要特性就是即插即用性,我们可以选择在需要的时候再加载动态库。
更改设置
如果不希望在软件一启动就加载动态库,需要将
1 | Targets-->Build Phases-->Link Binary With Libraries |
Dylib.framework对应的Status由默认的
Required改成
Optional;或者更干脆的,将
Dylib.framework从
Link Binary With Libraries列表中删除即可。
使用dlopen加载动态库
以
Dylib.framework为例,动态库中真正的可执行代码为
Dylib.framework/Dylib文件,因此使用dlopen时如果仅仅指定加载动态库的路径为
Dylib.framework是没法成功加载的。
示例代码如下:
12 | - (IBAction)onDlopenLoadAtPathAction1:(id)sender { NSString *documentsPath = [NSString stringWithFormat:@"%@/Documents/Dylib.framework/Dylib",NSHomeDirectory()]; [self dlopenLoadDylibWithPath:documentsPath]; } - (void)dlopenLoadDylibWithPath:(NSString *)path { libHandle = NULL; libHandle = dlopen([path cStringUsingEncoding:NSUTF8StringEncoding], RTLD_NOW); if (libHandle == NULL) { char *error = dlerror(); NSLog(@"dlopen error: %s", error); } else { NSLog(@"dlopen load framework success."); } } |
使用NSBundle加载动态库
也可以使用NSBundle来加载动态库,实现代码如下:
12 | - (IBAction)onBundleLoadAtPathAction1:(id)sender { NSString *documentsPath = [NSString stringWithFormat:@"%@/Documents/Dylib.framework",NSHomeDirectory()]; [self bundleLoadDylibWithPath:documentsPath]; } - (void)bundleLoadDylibWithPath:(NSString *)path { _libPath = path; NSError *err = nil; NSBundle *bundle = [NSBundle bundleWithPath:path]; if ([bundle loadAndReturnError:&err]) { NSLog(@"bundle load framework success."); } else { NSLog(@"bundle load framework err:%@",err); } } |
使用动态库中代码
通过上述任一一种方式加载的动态库后,就可以使用动态库中的代码文件了,以Dylib.framework中的
Person类的使用为例:
12 | - (IBAction)onTriggerButtonAction:(id)sender { Class rootClass = NSClassFromString(@"Person"); if (rootClass) { id object = [[rootClass alloc] init]; [(Person *)object run]; } } |
Person类是不成功的:
12 | - (IBAction)onTriggerButtonAction:(id)sender { Person *object = [[Person alloc] init]; if (object) { [object run]; } } |
监测动态库的加载和移除
我们可以通过下述方式,为动态库的加载和移除添加监听回调:12 | + (void)load { _dyld_register_func_for_add_image(&image_added); _dyld_register_func_for_remove_image(&image_removed); } |
从这里看出,原来就算空白工程软件启动的时候也会加载多达一百二十多个动态库,如果这些都是静态库,那该有多可怕!!
Demo
本文使用的例子已经上传到github上,需要的朋友请自取。另外,本文对某些东西可能有理解错误的地方,还请指出。
参考文档:
Framework Programming GuideOS X Man Pages
New Features in Xcode 6 Beta
ImageLogger
Dynamic Linking
Dynamic loading
Integrating Reveal with your iOS app
IOS Framework制作全攻略
Build Settings中的变量@rpath,@loader_path,@executable_path
深入浅出Cocoa之Framework
linux中静态库和动态库的区别和汇总
Posted by 王中周 Jun
12th, 2014 WWDC2014
相关文章推荐
- 给IOS项目添加图标和启动页
- iOS,开发准备之申请证书 ---by吴帮雷
- IOS行货自动打包
- iOS复制内容到剪切版
- IOS开发基础知识碎片-导航
- 苹果开发者各地区联系电话
- iOS IBInspectable和IB_DESIGNABLE
- IOS响应式编程框架ReactiveCocoa(RAC)使用示例
- iOS定位操作,获取当前位置
- github优秀开源项目大全-iOS
- 获取iOS设备唯一标识
- iOS中的单例
- WWDC总结:开发者需要知道的iOS 9 SDK新特性
- IOS Quartz 各种绘制图形用法---实现画图片、写文字、画线、椭圆、矩形、棱形等
- ios动画 calyer-旋转,缩放,裁剪,阴影,平移等
- IOS之NSTimer不一般
- IOS菜鸟的所感所思(十一)——统计文本中单词出现的次数并按照次数高低排序
- 仿iOS图标抖动
- 什么时候应该使用Autorelease Pool
- iOS取照片库的缩略图和大图