RyukieDev
  • 关于我-AboutMe
  • 我的作品-MyApps
    • 「梦见」账本
      • 「梦见」账本(Umemi):极致的记账体验
      • 隐私协议:Privacy Policy
      • 服务协议:Terms of use
      • 外观预览:Preview
        • 赛博朋克-Cyberpunk
        • 樱-Sakura
        • 初恋-FirstLove
        • 永生-Eternal
        • 菲尼克斯-Phoenix
        • 报丧女妖-Banshee
        • 九霄-NYXL
        • Dream
        • 猕猴桃-Kiwi
        • 蜂蜜-Hachimitsu
        • DC
    • Elic-扫雷无尽天梯
    • 隐私访问记录
      • 03.如何分析iOS15隐私访问记录
      • PrivacyPolicy
      • FrameWorks
    • 醒词
      • PrivacyPolicy
      • TermsOfUse
    • 一色
      • PrivacyPolicy
    • 醒诗
      • PrivacyPolicy
    • 醒词键盘
      • PrivacyPolicy
    • 中文数字键盘
      • PrivacyPolicy
  • 独立开发
    • 产运
      • 01.没钱推广?这忘了这100美元
      • 02.在个人站点配置app-ads
      • 03.应用图标圆角
      • 04.iOS独立开发者注册公司到App备案上架.md
    • iCloud
      • 01.基于iCloud构建用户体系
      • 02.基于iCloud构建游戏内排行榜
  • Swift
    • 01.纯Swift路由方案探究
    • 02.使用Carthage替代CocoaPods
    • 03.逃逸闭包和非逃逸闭包
    • 04.向下向上取整
    • 05.Copy-on-write
    • 06.OC老项目Swift混编的一些坑
    • 07.OC项目中加入Swift混编
    • 08.Optional实质
    • 09.R-Swift-安全的资源组织方案forSwift
    • 10.Struct与Class
    • 11.Swift5新特性
    • 12.Swift性能分析
    • 13.SwiftPackage使用
    • 14.String与Substring
    • 15.Array,Set,Dictionary
    • 16.For-in跳跃遍历
    • 17.Switch元祖
    • 18.循环的标签控制
    • 19.Protocol与静态派发、动态派发
    • 20.Swift位移枚举
    • 21.Swift轻量级网络封装:SwiftyServiceProtocol(适用于混编或纯Swift项目)
    • 22.open与public
    • 23.Swift项目编译速度优化
    • 24.[译]编写高性能Swift代码-Writing High-Performance Swift Code(2022.8.25版)
    • 25.Swift编译流程
    • 26.Swift方法调度
  • SwiftUI
    • 01.Form
    • 02.Navigation
    • 03.ViewBuilder参数10个限制
    • 04.UIKit混编时Dismiss掉HostController
    • 05.如何在SwiftUI中使用ImagePicker?
    • 06.从some看Swift不透明类型
    • 07.TabView使用
    • 08.openURL
    • 09.Search
    • 10.SwifUI中使用WKWebView
  • DeepLearning
    • 基础知识
      • 01.感知机与神经网络
      • 02.线性可分
    • TensorFlow
      • 01.Anaconda
      • 02.JupyterNotebook
      • 03.安装TensorFlow
  • iOS
    • 底层
      • 01.alloc与字节对齐
      • 02.结构体内存对齐
      • 03.对象本质探究与isa
      • 04.ISA与Class
      • 05.深入探索Class的结构
      • 06.WWDC20-runtime优化
      • 07.深入探究属性
      • 08.isKindOfClass的底层实现
      • 09.slowpath和fastpath
      • 10.Class-cache_t
      • 11.源码解读objc_msgSend
      • 12.类的实现与初始化源码解读
      • 13.动态决议与消息转发
      • 14.iOS应用启动(一):dyld与main函数
      • 15.iOS应用启动(二):环境配置与runtime初始化
      • 16.iOS应用启动(三):镜像文件的读取和加载
      • 17.iOS应用启动(四):分类的加载
      • 18.关联对象源码解析
      • 19.MethodSwizzing方法交换的坑
      • 20.详解KVC
      • 21.KVO几个被忽视的细节
      • 22.KVO底层原理
      • 23.多线程原理与atomic
      • 24.任务与队列的几个面试题
      • 25.dispatch_once单例实现原理
      • 26.栅栏函数
      • 27.信号量
      • 28.锁|性能分析
      • 29.锁|@synchronized
      • 30.锁|递归锁
      • 31.锁|NSConditionLock
      • 32.关于Block你所该知道的一切
    • 内存管理
      • 01.从一个面试题看TaggedPointer
      • 02.Retain&Release
      • 03.SideTable和weak底层实现
      • 04.Timer优化
      • 05.自动释放池与Runloop
      • 06.dealloc
    • 编译器
      • 01.LLVM
    • 杂项
      • 01.堆栈的深度问题
      • 02.使用TTF字体
      • 03.为什么选VIPER
      • 04.项目路由方案
      • 05.隐藏导航栏下面的线
      • 06.源代码到IPA
      • 07.iOS重签名调研
      • 08.load与-initialize
      • 09.NSTimer与GCD
      • 10.NSURLConnection-和-NSURLSession
      • 11.Storyboard中UnwindSegue的使用
      • 12.UI调试-UIDebuggingInformationOverlay
      • 13.UIWebView和WKWebView
      • 14.UIWebView自适应高度
      • 15.weak实现原理
    • Runloop
      • 01.RunLoop
      • 02.autoreleasepool
    • Runtime
      • 01.基本操作
      • 02.实现NSCoding的自动归档和自动解档
      • 03.消息机制
      • 04.重写description打印对象信息
      • 05.MethodSwizzling的问题
    • 优化
      • 01.Apple官方资源瘦身方案ODR(一):初见
      • 02.Apple官方资源瘦身方案ODR(二):践行|换肤系统改造
      • 03.二进制重排实践
      • 04.iOS截屏防护方案
      • 05.提高编译速度
      • 06.图片格式-WebP
      • 07.App启动速度优化
      • 08.IDL自动化埋点
      • 09.渲染原理及优化
      • 10.「利用 Metrics 和 Diagnostics 提高性能」网络研讨活动
      • 11.离屏渲染
      • 12.一键搞定iOS16横竖屏切换
    • 多线程
      • 01.合适的线程数量
      • 02.死锁
      • 03.为什么用dispatch-once实现单例
      • 04.iOS多线程方案
      • 05.iOS多线程技术对比
    • Database
      • 01.数据库主键和外键
      • 02.FMDB-死锁问题
      • 03.FMDB与WCDB
      • 04.SQLite数据库修复
    • 架构
      • 01.组件化
  • 逆向
    • 01.寄存器
    • 03.iOS应用签名原理
    • 04.利用Xcode进行重签名与调试
    • 05.dylib注入
    • 06.MachO文件
    • 07.dyld
    • 08.Hook
    • 09.深入理解动态库与静态库
    • 10.通过符号表找到符号
    • 11.fishhook原理
    • 12.去符号与恢复符号
    • 13.反HOOK防护(一):基于Fishhook
    • 14.反HOOK防护(二):Monkey
    • 15.Inlinehook:Dobby
    • 16.LLDB
    • 17.虚拟内存
    • 18.Chisel工具
    • 19.DS.LLDB工具
    • 20.Cycript工具
    • 21.Cycrupt用法
    • 22.Logos
    • 23.应用砸壳
    • 24.实战人人视频破解
    • 25.解密被加密的数据库文件
  • Flutter
    • 01.初见Flutter
    • 02.Layout
    • 03.状态管理
    • 04.BottomNavigationBar
    • 05.MaterialApp
    • 06.android资源配置
    • 07.Positioned与Container嵌套无法充满容器
    • 08.Cell点击跳转
    • 09.代码规范
    • 10.通过联系人Cell看断言
    • 11.有状态Widget初始化重写&链式调用&排序
    • 12.索引条:手势及clamp函数
    • 13.ListView滑动到指定位置
    • 14.悬浮菜单列表
    • 15.Mock数据小技巧
    • 16.第三方库导入与网络数据异步请求与展示
    • 17.请求数据保留
    • 18.异步编程之Future
    • 19.Future&Microtask
    • 20.Dart异步编程:Isolates和事件循环
    • 21.Widget的生命周期
    • 22.Widget树&Render树&Element树
    • 23.Key
    • 24.调用原生相册
    • 25.iOS原生嵌入FlutterModule
  • 网络
    • 01 网络分层的优点
    • 02 网络理解
    • 03 iOS-网络安全之HTTPS
    • 04 POST和GET
    • 05 SSL-TLS四次握手
  • 直播技术
    • 01 直播技术相关
    • Socket-Little-Endian-Big-Endian
  • 知识点梳理
    • 01 面试算法题记录01
    • 02 面试题记录-C语言
    • 08 一套iOS底层试卷
    • 03 知识点梳理:iOS底层
    • 04 知识点梳理:网络
    • 05 知识点梳理:多线程
    • 06 知识点梳理:计算机基础
    • 07 知识点梳理:算法数据结构
    • 09 知识点梳理:HTML和浏览器
    • 10 知识点梳理:JavaSctipt
  • Framework
    • 01 CodeReading-01-YYModel
    • 02 RYImagePicker-iOS图片视频选择器
    • 03 RYImagesScroller-iOS高度自定义的图片轮播器
    • 04 RYPhotosBrowser
  • Issue
    • 01 使用KVC设置UIAlertAction按钮颜色的Crash
    • 02 iOS-常见崩溃分析
    • 03 UICollectionView的一些问题
  • OpenGL ES
    • 01.顶点着色器与片元着色器
  • 数据结构与算法
    • 剑指Offer-Swift
      • 03.找出数组中重复的数字
      • 04.二维数组中的查找
      • 05.替换空格
      • 06.从尾到头打印链表
      • 07.重建二叉树
      • 12.矩阵中的路径(回溯法)
      • 13.机器人的运动范围
      • 14.I.剪绳子
      • 14.II.剪绳子
      • 15.二进制中1的个数(含一个拓展问题)
      • 16.数值的整数次方
      • 18.删除链表的节点
      • 21.调整数组顺序使奇数位于偶数前面
      • 22.链表中倒数第k个节点
      • 24.反转链表
      • 25.合并两个排序的链表
      • 26.树的子结构
      • 27.二叉树的镜像
      • 28.对称的二叉树
      • 29.顺时针打印矩阵
      • 30.包含min函数的栈(容易被误导的一题)
      • 31.栈的压入、弹出序列
      • 32.I.从上到下打印二叉树
      • 32.II.从上到下打印二叉树II
      • 32.III.从上到下打印二叉树III
      • 32.从上到下花式打印二叉树
      • 33.二叉搜索树的后序遍历序列
      • 34.二叉树中和为某一值的路径
      • 35.复杂链表的复制(无Swift用例)
      • 36.二叉搜索树与双向链表
      • 37.序列化二叉树
      • 39.数组中出现次数超过一半的数字
      • 40.最小的k个数
      • 41.数据流中的中位数
      • 42.连续子数组的最大和
      • 43.1~n整数中1出现的次数
      • 44.数字序列中某一位的数字
      • 45.把数组排成最小的数
      • 46.把数字翻译成字符串
      • 47.礼物的最大价值
      • 48.最长不含重复字符的子字符串
      • 50.第一个只出现一次的字符
      • 52.两个链表的第一个公共节点
      • 53-I.在排序数组中查找数字
      • 53-II.0~n-1中缺失的数字
      • 54.二叉搜索树的第k大节点
      • 55-I.二叉树的深度
      • 55-II.平衡二叉树
      • 56-I.数组中数字出现的次数
      • 56-II.数组中数字出现的次数II
      • 57.和为s的两个数字
      • 58-I.翻转单词顺序
      • 58-II.左旋转字符串
      • 59-I.滑动窗口的最大值
      • 59-II.队列的最大值
      • 60.n个骰子的点数
      • 61.扑克牌中的顺子
      • 62.圆圈中最后剩下的数字
      • 63.股票的最大利润
      • 64.求1+2+…+n
      • 65.不用加减乘除做加法
      • 66.构建乘积数组
      • 67.把字符串转换成整数
      • 68-I.二叉搜索树的最近公共祖先
      • 68-II.二叉树的最近公共祖先
    • 技巧
      • 01.前缀和
      • 02.同余性质
      • 03.快速幂
      • 04.快速排序
      • 05.深度优先&广度优先
      • 06.冒泡排序
      • 07.摩尔投票
      • 08.优先队列
    • 数据结构
Powered by GitBook
On this page
  • 一、简单的区别
  • 1.1 静态库
  • 1.2 动态库
  • 1.3 体积
  • 1.4 启动速度
  • 1.5 各自优缺点
  • 二、什么是framework
  • 2.1 结构
  • 2.2 资源文件
  • 2.3 Embedded Framework
  • 三、CocoaPods
  • 参考

Was this helpful?

  1. 逆向

09.深入理解动态库与静态库

一、简单的区别

静态和动态是相对编译时和运行时进行区分的

1.1 静态库

静态库在编译时会被链接进MachO中

后缀一般为.a/.framework

1.2 动态库

在程序编译时不会被链接到MachO中,而是在程序启动的时候加载动态库到内存中。其中动态库分动态链接库和动态加载库两种

动态库文件一般为.tbd(以前是.dylib)/.framework

动态链接库

在编译阶段确定了依赖关系的动态库。当运行可执行文件时,如果尚未加载,则会将加载这些动态库。

常见的动态库都是这种

动态加载库

编译阶段不需要指定app需要依赖哪些动态库。当运行过程中需要加载某个动态库时,就会用dlopen函数动态的把库加载到内存中使用。

这种玩玩可以,上架就别想了。比通过网络如下载一个动态库,然后加载调用。

1.3 体积

一般来说,静态库直接拷贝进可执行文件,相较动态库对包体积的影响会大一些。

静态库被多个可执行文件依赖就会被拷贝多次。

1.4 启动速度

因为动态库在应用启动的时候需要加载,所以对应用的启动速度是有一定的影响的。

严谨的说,对于已经加载过的动态库已经存在于共享缓存中,那么对启动速度的影响就很小了。

1.5 各自优缺点

  • 静态库

    • 模块化,分工合作,提高了代码的复用及核心技术的保密程度

    • 避免少量改动经常导致大量的重复编译连接

    • 也可以重用,注意不是共享使用

  • 动态库

    • 可以将最终可执行文件体积缩小,将整个应用程序分模块,团队合作,进行分工,影响比较小

    • 多个应用程序共享内存中得同一份库文件,节省资源

    • 可以不重新编译连接可执行程序的前提下,更新动态库文件达到更新应用程序的目的

    • 应用插件化

    • 软件版本实时模块升级

    • 在其它大部分平台上,动态库都可以用于不同应用间共享, 共享可执行文件,这就大大节省了内存

在 iOS8 之前,苹果不允许第三方框架使用动态方式加载,从 iOS8 开始允许开发者有条件地创建和使用动态框架,这种框架叫做 Cocoa Touch Framework。

虽然同样是动态框架,但是和系统 framework 不同,苹果系统专属的 framework 是共享的(如 UIKit),使用 Cocoa Touch Framework 制作的动态库在打包和提交 app 时会被放到 app main bundle 的根目录中,运行在沙盒里,而不是系统中。

也就是说,不同的 app 就算使用了同样的 framework,但还是会有多份的框架被分别签名、打包和加载。

不过 iOS8 上开放了 App Extension 功能,可以为一个应用创建插件,这样主 app 和插件之间共享动态库还是可行的。

二、什么是framework

Framework 是 Cocoa/Cocoa Touch 程序中使用的一种资源打包方式,可以将代码文件、头文件、资源文件、说明文档等集中在一起,方便开发者使用。一般如果是静态 Framework 的话,资源打包进 Framework 是读取不了的。静态 Framework 和 .a 文件都是编译进可执行文件里面的。只有动态 Framework 能在 .app 下面的 Framework 文件夹下看到,并读取 .framework 里的资源文件。

Cocoa/Cocoa Touch 开发框架本身提供了大量的 Framework,比如 Foundation.framework/UIKit.framework 等。需要注意的是,这些 Framework 无一例外都是动态库。

平时用的第三方 SDK 的 Framework 都是静态库,真正的动态库是上不了 AppStore(iOS8 之后能上 AppStore,因为 App Extension,需要动态库支持)。

2.1 结构

Headers

表示暴露的头文件,一般都会有一个和 Framework 同名的 .h 文件,在创建 Framework 的时候文件夹里也会默认生成这样一个文件。有这个和 Framework 同名的 .h 文件 @import 导入库的时候编译器才能找到这个库。

info.plist

主要就是这个 Framework 的一些配置信息。

Modules

这个文件夹里有个 module.modulemap 文件

framework module DynamicFramework {
  umbrella header "DynamicFramework.h"

  export *

  module * { export * }

}

这里面有这样一句 umbrella header "DynamicFramework.h",umbrella 有保护伞、庇护的意思。

也就是说 Headers 中暴露的 DynamicFramework.h 文件被放在 umbrella 雨伞下保护起来了,所以我们需要将其他的所有需要暴露的 .h 文件放到 DynamicFramework.h 文件中保护起来,不然会出现警告。

@import 的时候也只能找到 umbrella 雨伞下保护起来的 .h 文件。

二进制文件(Unix 可执行文件)

这个就是你源码编译而成的二进制文件,主要的执行代码就在这个里面。

.bundle 文件

如果我们在 Build Phases -> Copy Bundle Resources 里加入 .bundle 文件,那么创建出来的 .Framework 里就会有这个 .bundle 的资源文件夹。

2.2 资源文件

CocoaPods 如何生成 Framework 的资源文件?

我们能看到用 cocoapods 创建 Framework 的时候,Framework 里面有一个 .bundle 文件,跟 Framework 同级目录里也有一个 .bundle文件。这两个文件其实是一样的。

那这两个 .bundle 是怎么来的呢?我们能看到用 use_frameworks! 生成的 pod 里面,pods 这个 PROJECT 下面会为每一个 pod 生成一个 target。

那么如果这个 pod 有资源文件的话,就会有一个叫 xxx-bundleName 的 target,最后这个 target 生成的就是 bundleName.bundle。

在 xxx 的 target 的Build Phases -> Copy Bundle Resources里加入这个 .bundle,在 Framework 里面就会生成这样一个 bundle。

在 xxx 的 target 的Build Phases -> Target Dependencies里加入这个target:xxx-bundleName,就会在 Framework 的同级目录里生成这样一个 bundle。

静态 Framework 里不需要加入资源文件。一般资源打包进静态 Framework 是读取不了的。

静态 Framework 和 .a 文件都是编译进可执行文件里面的。只有动态 Framework 能在 .app 的 Framework 文件夹下看到,并读取 .framework 里的资源文件。

你可以用 NSBundle * bundle = [[NSBundle mainBundle] bundlePath]; 得到 .app 目录,如果是动态库你能在 Framework 目录下看到这个动态库以及动态库里面资源文件。

然后你只要用 NSBundle * bundle = [NSBundle bundleForClass:<#ClassFromFramework#>]; 得到这个动态库的路径就能读取到里面的资源了。但是如果是静态库的话,因为编译进了可执行文件里面,你也就没办法读到这个静态库了,你能看到 .app 下的 Framework 目录为空。

2.3 Embedded Framework

报错 Reason: image not found

如果直接在工程里使用创建的动态库时候会出现此错误,需要在工程的 General 里的 Embedded Binaries 添加这个动态库才能使用。

因为创建的这个动态库其实也不能给其他程序使用的,而你的 App Extension 和 APP 之间是需要使用这个动态库的。这个动态库可以 App Extension 和 APP 之间共用一份(App 和 Extension 的 Bundle 是共享的),因此苹果又把这种 Framework 称为 Embedded Framework。

三、CocoaPods

在使用 CocoaPods 的时候在 Podfile 里加入 use_frameworks!,那么你在编译的时候就会默认帮你生成动态库,我们能看到每个源码 Pod 都会在 Pods 工程下面生成一个对应的动态库 Framework 的 target,我们能在这个 target 的 Build Settings -> Mach-O Type 看到默认设置是 Dynamic Library,也就是会生成一个动态 Framework,我们能在 Products 下面看到每一个 Pod 对应生成的动态库。

这些生成的动态库将链接到主项目给主工程使用,但是我们上面说过动态库需要在主工程 target 的 General -> Embedded Binaries 中添加才能使用,而我们并没有在 Embedded Binaries 中看到这些动态库。那这是怎么回事呢,其实是 cocoapods 已经执行了脚本把这些动态库嵌入到了 .app 的 Framework 目录下,相当于在 Embedded Binaries 加入了这些动态库。我们能在主工程 target 的 Build Phase -> Embed Pods Frameworks 里看到执行的脚本。

参考

Previous08.HookNext10.通过符号表找到符号

Last updated 3 years ago

Was this helpful?

iOS 静态库和动态库
初识iOS中的动态库和静态库
1
2