如何在 Xcode 工程中添加动态库(Dynamic Library)。
首先我们知道,对于 “.a 静态库” 和 “静态 framework”,直接把相关文件拖拽到工程中,并勾选 Copy if needed 选项即可,无需其它额外的设置;
而对于添加“动态 framework”,稍微比较麻烦,主要有以下几种方式。
PS:我们这里说的“添加动态库”是指第三方动态库,而不是像 UIKit.framework、Foundation.framework 或者 libc++ 等系统自带的动态库,对于它们的依赖添加很简单,直接在 General ->Linked Frameworks and Libraries 中点击加号搜索添加即可。
在 Xcode 工程中选中 app 对应的 target,然后在 General ->Embedded Binaries 下点击加号,如图 1,在d出的窗口选择 Add Other…,最后在 Finder 中选择你要添加的“动态 framework”,并勾选 Copy if needed 即可。需要注意的是,你不能直接在 Finder 中把 .framework 文件拖拽到 Embedded Binaries 中,否则会报错。
关于手动添加动态库的更多细节以及遇到问题的解决办法,可参考苹果官方的教程: 《Embedding Frameworks In An App》
但是!这种方式看似很方便,其实有个坑是:我们上一条小集提到,一般动态二进制文件都会包含很多处理器架构,例如:i386, x86_64, armv7, armv7s, arm64 等,然后 Xcode 在编译链接时,对动态二进制文件是直接拷贝到 .ipa 包中,并不会像链接静态库那样筛选掉未用到 architecture,而苹果又不允许把包含 i386, x86_64 等模拟器架构的包上传到 App Store Connect 后台,会报错。因此,我们在打 Release 正式包时往往需要手动通过 lipo 命令或者编写脚本移除掉这些 Invalid Architectures。(除非你的开发工程只通过真机来调试,不准备在模拟器里运行,且添加的动态库刚好又不包含 i386、x86_64)
对于通过 Carthage 集成的第三方库,在 Cartfile 文件中添加好依赖后,然后执行 carthage update 命令会帮我们生成一个个“动态 framework”,例如 AFNetworking.framework、SDWebImage.framework 等,然后把它们拖拽到工程中的 General ->Linked Frameworks and Libraries ,然后在配置相关拷贝脚本和命令,详细可参考 Carthage 的 Quick Start 教程。
这里有个关键 *** 作是,需要在 Xcode 工程的 Build Phases 中添加一个执行脚本(New Run Script Phase),并在脚本中执行如下命令:
如图 2 所示:
该命令的作用大概就是,在打包拷贝动态库时自动帮我们移除掉其中的 i386、x86_64。
同样地,通过 CocoaPods 集成动态库时,也会在工程中自动帮我们添加一个 Shell 脚本用于做这件事,如图 3 中的 [CP] Embed Pods Frameworks,
大家可以自行查阅该 Pods-xxx-frameworks.sh 脚本的内容,里面有个函数 strip_invalid_archs() 就是用于在打包时移除无用的处理器架构,如图 4:
因此,我们可以把自己开发的或者他人提供的动态 framework,通过 CocoaPods 来集成到工程中:创建一个 Pods 私有 git 库(相信大家已经很熟悉了),在 git 库中添加相关动态 .frameworks 文件,然后其 Podspec 文件的写法大致如图 5 所示,最后在你的工程中 pod install 即可。
最后我们思考一个问题:“静态 framework” 和 “动态 framework” 在使用上似乎也没什么不同,而工程添加 “动态 framework” 又比较繁琐,那么在 iOS/macOS 开发中什么情况下会使用动态库呢?
特定情况下不能使用cocoapods,需要手动导入三方框架,遇到过某些需要拿. xcodeproj的框架。例如GPUImage.
CoreMedia
CoreVideo
OpenGLES
AVFoundation
QuartzCore
Build Settings ->Header Search Paths 添加GPUImage的路径
framework 在GPUImage这个文件夹下,所以添加的路径为 GPUImage/framework 。
路径选择recursive!
recursive:遍历该目录,non-recursive:默认路径设置;不遍历该目录。如果路径的属性为recursive,那么编译的时候在找库的路径的时候,会遍历该目录下的所有子目录的库文件。PS:在搭建项目的时候,可以创建一个专门放库文件的文件夹并且设置其属性为recursive。$(PROJECT_DIR)/**相当于遍历项目文件同级下的所有路径(不推荐使用,项目大的话,影响编译的速度)。
如果说 CocoaPods 像一个航母, 一应俱全, 坚实稳固. 那么 Carthage 就像一艘巡洋舰, 机动灵活, 攻击迅速. 1
CocoaPods是已存在很长时间的Cocoa依赖管理器, 那么为什么要创建Carthage呢?
Carthage 基本的工作流程:
1>创建一个Cartfile,包含你希望在项目中使用的框架的列表
2>运行Carthage,将会获取列出的框架并编译它们
3>将编译完成的.framework二进制文件拖拽到你的Xcode项目当中
Carthage编译你的框架/库,然后提供该框架的二进制文件,但你仍然持有该项目结构和设置的绝对控制。Carthage不会自动的修改你的项目文件或编译设置。
相信大家可能遇到这种情况, Podfile中配置好相关框架/库 -> pod install -verbose -no-repo-update , 然后编译运行时, 出现类似错误:
接下来又是一系列的折腾, 白白浪费很多时间.
**CocoaPods 有如下优势: **
但是 CocoaPods 作为一个有中心仓库的解决方案, 缺点 也比较明显:
** Carthage 的优势: **
Carthage 的不足:
在这个过程当中,Carthage将创建一些 build artifacts ,其中最重要的是 Cartfile.lock
文件,里面将列出每个框架的具体版本,确保你提交了这个文件到版本控制工具里面(如Git、SVN),因为每个用到项目的人都需要它来编译相同版本的框架。
完成上面的步骤并提交你的修改,项目的其他用户就只需要获取该仓库并执行 carthage bootstrap 就能使用你所添加的框架。
添加框架到单元测试或另一个框架
使用Carthage添加框架到任意目标的方法,和添加到应用程序差不多。主要的不同在于框架是如何设置并链接到Xcode的。
因为非应用程序目标没有“Embedded Binaries”设置区域,你需要将编译完成后的框架拖拽到“Link Binaries With Libraries”的区域里。
在某些稀有案例中,你也许会想要复制每个依赖到已编译的项目中(比如,在外部框架中嵌入依赖,或确保依赖在测试工具中正常显示)。想要达到这个目的,你需要创建一个新的“Copy Files”编译选项和“Frameworks”组,然后将框架的引用添加到里面。
升级框架
如果你修改了Cartfile,或者你想升级到框架的最新版本(取决于你指定的需求版本),执行 carthage update 命令可以达到目的。
让你的框架支持Carthage
Carthage只正式支持动态框架 ,动态框架能够在任何版本的OS X上使用,但只能在 iOS 8及以上 版本使用。
因为Carthage拥有非中心化的包列表,以及没有项目指定的编译设置,大多数框架应该能自动编译。
分享你的Xcode schemes
Carthage将只从你的.xcodeproj 中标记为已分享的Xcode schemes来编译。如果你想检查编译是否成功,执行 carthage build --no-skip-current 命令,然后检查Carthage.build文件夹。
如果当执行命令但有scheme没有被编译,打开Xcode并确定对应scheme被标记为“Shared”,以便Carthage能够发现它。
解决编译失败
如果你在执行carthage build --no-skip-current
时编译失败,尝试执行 xcodebuild -scheme SCHEME -workspace WORKSPACE build 或 xcodebuild -scheme SCHEME -project PROJECT build (将其中的大写单词换成你项目的对应名称),然后观察是否有相同的失败发生,这应该能生成足够的失败信息来解决问题。
引用源
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)