理解Cocoapods

对于作 iOS 开发的朋友来讲,Cocoapods 是一件没必要可少的得利工具,它是一个管理第三方库,而且解决其依赖关系的工具,可是有不少朋友对其运做的机制知其然殊不知其因此然。笔者就在这里简单的讲解一下。ios

新石器时代

对于任何一项编程来讲,早期未造成工程化的时候,是不存在所谓依赖管理的概念的,iOS 也是同样,早期 iOS 开发若是想要使用第三方库,是很是繁琐的一件事情。git

  1. 将第三方库源代码复制到工程目录,或者使用 git submodule 将其做为项目的一个模块编程

  2. 设置工程文件,添加第三方库依赖的系统库xcode

  3. 对于某些第三方库,可能须要设置一些编译选项( etc. -fno-objc-arc架构

  4. 最后就是管理第三方库代码的更新工具

这些都是体力活,为了能省去这些工做,有没有办法呢?
答案是有的,iOS 开发终究仍是很传统的 Unix 开发,直接把第三方库源代码抽离出来,打包成静态库就好了(PS:在 iOS 8 以前苹果只容许使用静态库,而 iOS 8 后就能够打包动态库了,固然,其实是同样的。)。这样的话就不须要担忧过多的源代码导入的繁琐,也不须要担忧第三方库究竟需不须要编译选项,并且第三方库更新只须要更新静态库就好了。简直是美好的人生。ui

农耕时代

封装成静态库或动态库看起来确实美好了,方便快捷,这也是 Unix 下的解决方案。可是只要仔细一想,问题一大堆。spa

  1. 某些第三方库极可能直接依赖另外一项第三方库,依赖若是使用手工解决将会是很大的工做。版本控制

  2. 动态库不能用于 iOS 7 及如下版本code

  3. 工程依旧须要设置依赖的系统库

  4. 仍然须要手工更新第三方库版本

对于 Unix 环境来讲,动态库能够存放在系统默认搜索路径下,这样全部的应用均可以共享同一个内存副本,并且升级动态库的时候能够一块儿升级,不须要到各处寻找。可是 iOS 的动态库其实是缩水的,由于苹果将动态库限制在了沙盒内部,其余 App 彻底不能访问此动态库。这就限制了动态库的优势。还有一点缘由就是指令集架构的不一样,iOS 模拟器使用的是 x86 架构指令集,而真机则是 ARM64 等指令集,若是想要方便使用,最好须要打包通用架构的静态库,可是这是很繁琐的工做。
因为以上缘由,手工封装静态库或者动态库实际上在项目小的时候是能够的,可是项目规模一旦扩大就会致使效率低下。

工业时代

为了可以自动化流水做业,就引出了依赖包管理的概念,也就是 Cocoapods。Cocoapods 本质上仍是上面所说的封装动态库静态库,可是它解决的最大问题就是依赖管理。开发者不须要从 Github 的地方辛苦的寻找代码,只须要一条命令,就能下载整合第三方库。这些优势都没必要说,笔者下面就具体讲解 Cocoapods 到底对咱们的工程作了什么事情。
首先使用 Xcode 建立了一个工程,使用 git init 命令将其归入版本控制,作第一次提交。而后写 Podfile,直接跟随 Cocoapods 官网文档写最简单的内容。

使用 framework

platform :ios, '8.0'
use_frameworks!

target 'test' do
  pod 'AFNetworking', '~> 2.6'
end

而后输入如下命令整合第三方库。

> pod install

如今能够看一下修改的内容。

> git status

On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   test.xcodeproj/project.pbxproj

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    Podfile.lock
    Pods/
    test.xcworkspace/

因为输出过场,这里就不贴 git diff 命令的输出了,从 git diff 命令输出能够看出,主要修改了 .xcodeproj/project.pbxproj 文件的内容,而且将原先的文件格式转化为了 XML 文件格式。而且,能够看出来,添加了一个 工程名.xcworkspace 的工做空间,将原先的工程文件和新的 Pods 工程放到了同一个工做空间下。

<?xml version="1.0" encoding="UTF-8"?>
<Workspace
   version = "1.0">
   <FileRef
      location = "group:test.xcodeproj">
   </FileRef>
   <FileRef
      location = "group:Pods/Pods.xcodeproj">
   </FileRef>
</Workspace>

很显然,全部的配置都被放到了工程文件中,工做空间实际上只是一个工程的整合。
因为文件格式不一样,没法很好的对比反映工程文件到底哪里被修改了,可是从实际的工程打开后观察,也能稍微了解。总结以下:

  1. 在 General -> Linked Frameworks and Libraries 中添加了 Pods_test.framework 的依赖

  2. Build Settings -> Other Linker Flags 中添加了 -framework "AFNetworking"

  3. Build Settings -> RunPath Search Paths 中添加了 @executable_path/Frameworks

  4. Build Settings -> Other C Flags 添加 -iquote "$CONFIGURATION_BUILD_DIR/AFNetworking.framework/Headers" 和 Other C++ Flags 添加 $(OTHER_CFLAGS),也就是说,跟随 Other C Flags 配置

  5. Build Settings -> Preprocessor Macros 添加 COCOAPODS=1

  6. Build Settings -> User-Defined -> MTL_ENABLE_DEBUG_INFO PODS_FRAMEWORK_BUILD_PATH PODS_ROOT 三个变量

  7. Build Phases -> Embed Pods Frameworks 添加 "${SRCROOT}/Pods/Target Support Files/Pods-test/Pods-test-frameworks.sh"

  8. Build Phases -> Copy Pods Resources 添加 "${SRCROOT}/Pods/Target Support Files/Pods-test/Pods-test-resources.sh"

从上面能够看出,若是在 Podfile 中指定了 use_frameworks! 则会使用动态库封装其内容,而上面所作的主要工做就是添加对另外一个工程的依赖,添加连接器选项使其连接 framework,将动态库运行时搜索路径设置为 @executable_path/Frameworks 也就是说 ${BUNDLE_ROOT}/Frameworks,设置 C 和 C++ 编译器的头文件搜索路径,将 framework 放置到沙盒目录
而后再来看 Pods 工程,Pods 工程将每一个第三方库都使用一个 target 表示,还有一个 target 则是用于生成主要的库文件,须要注意的是,虽然第三方库的 target 生成的是动态库,可是最终的 target 生成的是静态库,可是只是起一个集合的做用,实际的二进制代码仍是被存放在各个动态库中,其主要修改了 Build Settings 内容

  1. 将 framework 的输出路径指定为 ${SRCROOT}/../build

  2. 指定 iOS Deployment Target 为原先 Podfile 中指定的版本,这是一个容易被人忽视的地方,不少朋友都觉得 Podfile 中 platform 指令指定的是主工程的 deployment target,其实是指定 Pods 工程的每一个 target

主要就是这两点,其余都是一些细碎的细节,好比将输出类型指定为动态库,设置第三方库依赖。
而后就是 Pods-工程名-frameworks.shPods-工程名-resources.sh,这两个文件实际上就是将封装通用架构动态库文件和将动态库复制到 bundle 指定目录下。有兴趣的朋友能够仔细看看。

不使用 framework

framework 只能在 iOS 8 以上平台使用,可是大多数状况下,工程都是须要兼容 iOS 7 版本的,因此 framework 功能只能舍弃掉,由于目前兼容版本都是以 UI 特征来划分兼容版本,iOS 6 及之前版本都算拟物化 UI,而 iOS 7 及之后版本则是扁平化风格。
这里先将 Podfile 中的 use_frameworks! 删除掉,再 pod install
经过 git diff 命令能够看到,实际上两种方式差异不大,只是不使用动态库而是使用静态库替代了全部的动态库,而后在 Other Linker Flags 中添加了 -ObjC和连接器命令连接所依赖的系统 framework,原先则是在 Pods 工程具体的 target 中才存在连接器命令连接系统 framework。并且还发现,在 Header Search Path 中添加了头文件的搜索路径。

后记

Cocoapods 虽然侵入性很强,可是对于新手来讲,屏蔽了不少底层的操做,很是便于实践,对于重复的工做也获得了很好的替代,若是有朋友想要补充,能够在下方留言指正。

相关文章
相关标签/搜索