美文网首页iOS SDK 开发总结iOS进阶之Frameworks开发移动端开发
二、cocopods 中的动态库、静态库和framework

二、cocopods 中的动态库、静态库和framework

作者: TankXie | 来源:发表于2019-02-17 01:01 被阅读35次

    写在前面

    前文中,梳理了iOS 平台下的 动态库静态库framework之间的关系,可以用如下一句话概括:

    • 就是一个二进制文件,有动态和静态之分
    • framework 是的一种打包方式

    在实际开发场景中,我们使用 cocopods 这个工具进行代码组件化管理:

    • 我们使用 cocopods 创建 pod 库进行代码组件开发,然后通过 podfile 在其它地方使用
    • 使用 cocoapods-packager 工具将 pod 库打包成 framework 对外输出

    本文从如下两个大的方面来介绍,cocopods 中的动态库、静态库:

    image.png

    本文使用的 cocopods 版本是 1.5.2,Xcode 版本是 Version 10.1 (10B61)。

    ➜  iOSFrameworkDemo git:(master) ✗ pod --version
    1.5.2
    

    1. 制作 pod 库 WBSDK

    制作教程网上有很多,这里就不 step by step 来做了。

    CocoaPods 私有仓库的创建(超详细)

    这里,创建一个名为 WBSDK 的 pod 库来演示。

    2. 使用 WBSDK

    使用 pod lib create 工具提供的模板创建的仓库中,Example 工程的 podfile 文件如下:

    use_frameworks!
    
    platform :ios, '8.0'
    
    target 'WBSDK_Example' do
      pod 'WBSDK', :path => '../'
    
      target 'WBSDK_Tests' do
        inherit! :search_paths
      end
    end
    
    

    我们把最外层的 Example 工程称之为壳工程,壳工程要使用 pod 依赖 WBSDK。

    ➜  WBSDK git:(master) ✗ tree -L 2
    .
    ├── Example
    │   ├── Podfile
    │   ├── Podfile.lock
    │   ├── Pods
    │   ├── Tests
    │   ├── WBSDK
    │   ├── WBSDK.xcodeproj
    │   └── WBSDK.xcworkspace
    ├── LICENSE
    ├── README.md
    ├── WBSDK
    │   ├── Assets
    │   └── Classes
    ├── WBSDK.podspec
    └── _Pods.xcodeproj -> Example/Pods/Pods.xcodeproj
    
    13 directories, 6 files
    

    壳工程使用 WBSDK 的时候,并不是直接以源码的方式引入使用,而是以二进制库的方使用的

    壳工程使用 WBSDK 的方式有两种:

    • 静态库
    • 动态库

    这个通过 podfile 中的 use_frameworks! 控制。

    2.1 以动态库的方式使用 WBSDK

    首先,在 podfile 中写入 use_frameworks!,执行 pod install 命令,运行 Example 工程。

    在 Xcode 中查看运行日志,某一次运行的截图如下:

    image.png

    上图中,我们可以看出 Build 的基本顺序入下:

    • Project Pods 下面的 target
    • Project WBSDK 下面的 target

    现在,我们需要观察一下 Pods 这个 project,我们聚焦于 WBSKD.framework 上面。

    image.png

    我们发现,WBSKD.framework 的 mach-o type 是以 dynamic 的方式打包。
    我们可以查看 Example 运行后的 .app 文件结构,查看结构如下:

    ➜  WBSDK_Example.app tree -L 2
    .
    ├── Base.lproj
    │   ├── LaunchScreen.storyboardc
    │   └── Main.storyboardc
    ├── Frameworks
    │   └── WBSDK.framework
    ├── Info.plist
    ├── PkgInfo
    ├── WBSDK_Example
    ├── _CodeSignature
    │   └── CodeResources
    └── en.lproj
        └── InfoPlist.strings
    
    7 directories, 5 files
    

    WBSDK.framework 独立于 WBSDK_Example 这个可执行文件存在,也验证了我们上面的说法。

    2.2 以静态库的方式使用 WBSKD

    我们去掉 podfile 中的 use_framework! 之后,再次执行 pod install,然后重新运行代码。

    使用同样的方式来验证 WBSDK 的引入方式,我们发现,此时壳工程以静态库 .a 的形式来依赖 WBSDK。

    验证方式与 2.1 相同,此处不赘述。

    3. 使用 cocoapods-packager 工具打包 framework

    3.1 安装 cocoapods-packager

    cocoapods-packagerGitHub 地址。

    官方给出了安装教程,安装完成之后,在终端输入 pod package,查看这个工具的基本使用如下。

     $ pod package NAME [SOURCE]
    

    两个基本参数:

    • NAME: 需要打包仓库名称,必填参数
    • SOURCE: pod repo地址,可选参数,默认是官方 repo

    3.2 相关的参数

    这里,我们只看和打包输出framework类型相关的参数 ,我们这里结合源码来理解这些参数。

    这里我们主要研究三个参数,以及默认不传参数的情形:

    • --embedded
    • --library
    • -dynamic
    • 默认不传

    package.rb 中,我将和打包类型相关的源码抠出来,分析一下。

      ['--embedded',  'Generate embedded frameworks.'],
      ['--library',   'Generate static libraries.'],
      ['--dynamic',   'Generate dynamic framework.'],
    

    --library--dynamic

    从三个参数的名称和解释中,这两个是没有歧义的:

    • --library,表示以 .a 的形式输出静态库
    • --dynamic,表示以 .framework 的形式输出动态库,按照之前我们的分类标准,是 Embedded Framework,如下图所示
    image.png

    那么问题来了,--embedded 是个什么东东?用这个参数打出来的究竟是动态库还是静态库?

    --embedded

    我们查看 initialize(argv) 函数。

    def initialize(argv)
    @embedded = argv.flag?('embedded')
    @library = argv.flag?('library')
    @dynamic = argv.flag?('dynamic')
    
    @package_type = if @embedded
                      :static_framework
                    elsif @dynamic
                      :dynamic_framework
                    elsif @library
                      :static_library
                    else
                      :static_framework
                    end
    # ……
    end
    

    builder.rb 中,build() 函数声明如下:

    def build(package_type)
      case package_type
      when :static_library
        build_static_library
      when :static_framework
        build_static_framework
      when :dynamic_framework
        build_dynamic_framework
      end
    end
    

    综上,我们发现使用 --embedded 参数,会以 .framework 的形式输出静态库,按照之前我们的分类标准,也就是 Static Framework,如下图所示:

    image.png

    从源码中也可以看出,在不带参数的默认情况下,输出的也是 Static Framework。

    默认参数和 --embedded 的区别

    我们通过上面源码发现,不带参数 和加上--embedded 参数结果都是打包静态framework,它们有区别么???

    换言之,我们能说默认参数是 --embedded 么?

    答案是否定的,在目录打包输出的目录结构上还是有些许差异。

    下面抠出了相关代码,这部分代码结合3.4一起看。

    def framework_path
      if @embedded
        @spec.name + '.embeddedframework' + '/' + @spec.name + '.framework'
      else
        @spec.name + '.framework'
      end
    end
    
    # package.rb
    builder.build(@package_type)
    
    return unless @embedded
    builder.link_embedded_resources
    
    # builder.rb
    def link_embedded_resources
      target_path = @fwk.root_path + Pathname.new('Resources')
      target_path.mkdir unless target_path.exist?
    
      Dir.glob(@fwk.resources_path.to_s + '/*').each do |resource|
        resource = Pathname.new(resource).relative_path_from(target_path)
        `ln -sf #{resource} #{target_path}`
      end
    end
    

    总结

    cocoapods-packager 通过三个参数来控制打包类型的:

    • --library,以 .a 的形式输出静态库
    • --dynamic,以 .framework 的形式输出动态库,也就是我们前文讲 的 Embedded Framework
    • --embedded.framework 的形式输出静态库,对应我们前文讲 的 Static Framework
    • 默认不传参数,也会输出 Static Framework。

    这里需要注意:--embeddedEmbedded Framework 的区别,不要混为一谈,二者有本质区别。

    3.4 使用 cocoapods-packager 打包

    为了测试方便,我们直接使用本地代码来打包,修改一下 WBSDK.podspec 中的Source 地址,指向本地仓库。

    s.source = { :git => '/Users/xieshoutan/Code/Blog/pods/WBSDK' }
    

    我们在 pod package 命令中加入 --force 参数,本次打包脚本强制执行,会覆盖上一次打包结果。

    打包 Static Framework(默认不带参数)

    使用默认 pod package 命令打包静态库:

    ➜  WBSDK git:(master) ✗ pod package WBSDK.podspec --force
    

    打包输出的文件放在 WBSDK-0.1.0 文件夹下,查看输出结果:

    ├── WBSDK-0.1.0
    │   ├── WBSDK.podspec
    │   ├── build
    │   │   ├── Pods.build
    │   │   └── XCBuildData
    │   └── ios
    │       └── WBSDK.framework
    

    我们可以验证 WBSDK.framework 是一个静态库。

    build 文件夹下面是本次编译打包的日志。

    打包 Static Framework(--embedded)

    使用 pod package 命令加上--embedded,打包静态库:

    ➜  WBSDK git:(master) ✗ pod package WBSDK.podspec --embedded --force
    

    打包输出的文件放在 WBSDK-0.1.0 文件夹下:

    ├── WBSDK-0.1.0
    │   ├── WBSDK.podspec
    │   ├── build
    │   │   ├── Pods.build
    │   │   │   └── Release-iphonesimulator
    │   │   └── XCBuildData
    │   │       ├── BuildDescriptionCacheIndex-5324f43b9a88d4ed571fe98b8ba8ab33
    │   │       ├── build.db
    │   │       ├── f2a06309409592aa39514fee692f5f80-desc.xcbuild
    │   │       └── f2a06309409592aa39514fee692f5f80-manifest.xcbuild
    │   └── ios
    │       └── WBSDK.embeddedframework
    │           ├── Resources
    │           └── WBSDK.framework
    

    我们发现,和不带参数的静态库相比,这次打包结果文件目录结构发生了一些变化:

    • WBSDK.embeddedframework 对输出结果进行了一次封装
    • WBSDK.framework 同级目录多了一个 Resource 文件夹,如果在 .podsec 中有资源文件引入,Resource 文件夹下会有对应的 bundle 文件

    上一节最后列出了与之相关的源码,可以结合查看,辅助理解。

    打包 Embedded Framework(--dynamic)

    使用 pod package 命令打包动态库,后面添加一个 --dynamic 参数。

    ➜  WBSDK git:(master) ✗ pod package WBSDK.podspec --dynamic --force
    

    打包输出的文件的动态库放在 WBSDK-0.1.0 文件夹下:

    ├── WBSDK-0.1.0
    │   ├── WBSDK.podspec
    │   └── ios
    │       ├── WBSDK.framework
    │       └── WBSDK.framework.dSYM
    

    4. 总结

    至此,我们在本篇中,研究了和cocopods相关的动态库、静态库以及framework的基础知识。

    但是对于“资源引用”、“pod库中动态库、静态库或者framework的引用”等知识没有涵盖。这一部分内容会在后面的文章中讲述。

    参考资料

    https://developer.apple.com/library/archive/technotes/tn2435/_index.html

    cocoapods的静态库和动态库

    Embedding Frameworks In An App

    Pod Authors Guide to CocoaPods Frameworks

    Link Binary with libraries VS Embed Frameworks

    An Introduction to Creating and Distributing Embedded Frameworks in iOS

    How do I use Cocoapods in an embedded framework?

    Name Mangling

    CocoaPods 都做了什么?

    相关文章

      网友评论

        本文标题:二、cocopods 中的动态库、静态库和framework

        本文链接:https://www.haomeiwen.com/subject/ggyweqtx.html