iOS App启动优化:动态库手动加载

一、前言

在介绍动态库手动加载方式之前,我们简单了解下动态库,又名共享库在iOS中是个特殊的存在,除了系统库以外,在大部分使用场景下(除了App Extension可以共享)其实并不能达到共享的目的。在iOS开发中动态库主要有以下用途:

  • 解决苹果审核iOS8__Text 字段60M限制,将独立的代码封装到动态库,进而减小可执行文件代码段的大小。

  • 制作第三方库,因为动态库没有像静态库之间的符号冲突问题(Xcode会有冲突日志,不影响运行),很多时候第三方库往往会以动态库的形式存在。

不同于静态库会被一起链接到Mach-O文件中,动态库是独立于主程序存在的。我们使用动态库时一般是直接拖到工程中,设置下Embed,使用起来非常方便。这些动态库是在App启动的时候通过dyld(动态链接器)根据依赖关系递归的加载到内存中,这样的方式称为动态库自动加载。但是如果动态库数量多了,会大大的拖慢应用的启动速度,因为dyld在rebasebinding阶段比较耗时。

那么,对于动态库使用比较多的项目怎么去优化App启动的耗时呢?其实除了自动加载方式,还有一种是手动加载(也称为懒加载),我们可以将一些不常用的动态库模块使用手动加载方式。

二、使用

动态库手动加载有两种方式可以实现:

  • dlopen;

  • NSBundle load/loadAndReturnError;

苹果在审核条款中明确禁止使用dlopen(感谢@
iOSLover的分享,和审核团队确认:加签过的动态库可以使用dlopen。本人未做验证,仅供参考。),我们重点看下NSBundle load/loadAndReturnError的方式,load的方式底层也是使用dlopen实现,只是增加了验签,而签名是在App打包的时候完成。如果从其他途径(如网络下载)获取的动态库是无法完成验签的

手动方式加载方式如下:

  1. 在Build Phases中点击"+"-"New Copy Files Phase",新增Copy Files选项,如果有动态库Strip的脚本,需要将Copy Files拖到前面,保证在打包时可以执行去除i386/x86_64指令集;

  2. 修改Copy Files 中的Destination选项为Frameworks,这样手动加载的动态库也会和其他动态库拷贝到同一个目录,点击"+"-"Add Others..."添加需要手动加载的动态库;

    Xcode截图

现在,我们可以使用了(因为是动态加载的,调用方式也只能是动态调用):

NSString *path = [[NSBundle mainBundle] pathForResource:@"MyLib" ofType:@"framework" inDirectory:@"Frameworks"];
NSError *err = nil;
NSBundle *bundle =  [NSBundle bundleWithPath:path];
if ([bundle loadAndReturnError:&err]) {
    //加载成功,方法调用
   Class c = NSClassFromString(@"MyClass");
   [c performSelector:@selector(printLog)];
}
else {
  //加载失败
}

二、扩展

上面的使用方式比较适合没有依赖的动态库。那么,我们能不能将一个业务模块转成动态库呢?业务模块往往会依赖各种各样的库,如网络库,埋点库,UI组件库等等...。而这些库可能是静态库,也可能是动态库。先看下静态库/动态库的打包时的依赖的特性:

  • 静态库依赖静态库,只引用,相互独立;

  • 静态库依赖动态库,只引用,相互独立;

  • 动态库依赖动态库,只引用,相互独立;

  • 动态库依赖静态库,链接到一起;

从上面的特性可以看出,动态库如果依赖静态库会“合并”静态库。这样被依赖的静态库在项目中有多份“拷贝”,这会大大增加包大小。制作动态库时可以这样做:

  1. 在动态库工程制作动态库的时候,删除Link Binary With Libraries中依赖的静态库,保留工程目录下的引用不要删除;
    Link Binary With Libraries
  1. "other linker Flags" 中添加-undefined dynamic_lookup
    other linker Flags

这样打包出来的动态库就不会包含静态库了...

因为动态库引用了主执行文件(静态库最后会被链接到主执行文件)的符号,所以主工程的配置也需要跟着修改:
"Build Settings"-"Strip Style" 修改为Non-Global Symbols,将外部引用的符号保留,当然这会略微增加包大小。

Strip Style

三、加载成功率 & 性能

从线上监控数据来看未发现加载失败的情况,成功率可达100%。加载耗时跟设备性能、特别是动态库符号(类名,协议,方法名等)数量有关。97% 以上几乎在用户无感知的情况下加载完成(毫秒级)。手动加载的效率比自动加载效率低,请勿在app启动过程中使用。

四、结束语

以上是动态库手动加载的使用方式,随着越来越多的App放弃iOS8,使用动态库来解决__Text 大小限制的需求变得越来越少。但可以作为App启动优化中动态库部分的优化方案(成本低,效果好)。对于组件化(如CocoaPods)构建的工程,上述的配置方案会有不同,但是原理一样。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345

推荐阅读更多精彩内容

  • 动态链接,在可执行文件装载时或运行时,由操作系统的装载程序加载库。大多数操作系统将解析外部引用(比如库)作为加载过...
    小5筒阅读 5,476评论 0 3
  • sdk开发笔记基础: 说到动态库,就不得不提静态库。静态库可以看做是一个具有特定功能的代码块,如果app中引用了静...
    F麦子阅读 6,477评论 0 17
  • //联系人:石虎QQ: 1224614774昵称:嗡嘛呢叭咪哄 一 、IOS开发APP启动原理 main()函数是...
    石虎132阅读 4,024评论 0 20
  • 前面介绍过制作过程,这里不讲如何制作动态库、静态库。 静态库和动态库都是以二进制提供代码复用的代码库。 静态库常见...
    纸简书生阅读 22,632评论 10 96
  • 起因 理论功底 动态库和静态库 介绍 静态库和动态库的区别 举个例子, iOS 项目中使用 Embeded Fra...
    leverkusen188阅读 1,009评论 0 3