CocoaPods深入一点

本文梳理了如下一些问题

  1. 关于Cocoapods
  2. –verbose,–no-repo-update
  3. pod install --verbose的过程
  4. podfile 和 podspec
  5. 看点CocoaPods源码
  6. Podfile.lock 和 Manifest.lock
  7. pod install 和 update的区别
  8. 那些常见的目录&指令
  • 期望用更简洁的话,做一些整理

关于Cocoapods
  • 管理Xcode项目依赖库的工具

项目依赖被详细写在Podfile的文件中,CocoaPods解决libraries之间的依赖关系、获取目标库的源码,并将它链接到Xcode workspace中来构建项目。最终目标是建立一个查找效率高效、更规范的第三方开源库生态环境


–verbose,–no-repo-update
  • pod install/update --no-repo-update:默认情况下install/update时,会默认更新一次podspec索引,使用–no-repo可以禁止对其索引的更新(这里说的就是local spec)
  • pod install/update --verbose:verbose表示显示详细的冗长的过程,没什么特殊的功能性的意义,只是把详细的过程列出来给你看,更有助于了解底层运行

podfile 和 podspec
  • 高度定制所需要的三方库
  • 描述文件,描述pod库的版本。描述一个库怎么被添加到工程中,支持:列出源文件、依赖库、编译选项和其他第三方库需要的配置。
    • 拿三方库举例,pod项目的podspec都托管在“https://github.com/CocoaPods/Specs”这个远程索引库
    • pod setup时,CocoaPods会将这些podspec索引文件更新到本地”~/.cocoapods/”目录下

pod install --verbose
  • Analyzing dependencies:依赖解析
    • Inspecting targets to integrate:检查要集成的目标
    • Resolving dependencies of Podfile:解析Podfile-版本控制和冲突:Milinillo依赖解决算法
    • Comparing resolved specification to the sandbox manifest
  • Downloading dependencies:下载依赖
    • 如下,installing是会下载到~/Library/Caches/CocoaPods/Pods/Release/…下,然后copy到当前工程的Pods目录下
    -> Installing AFNetworking (2.5.4.1)
    > Copying AFNetworking from
    `/Users/username/Library/Caches/CocoaPods/Pods/Release/AFNetworking/2.5.4.1-313e5`
    to `Pods/AFNetworking`
    
    也可能已存在,就是using
    -> Using AFNetworking (2.5.4.1)
    
  • Generating Pods project
Generating Pods project
  - Creating Pods project
  - Adding source files to Pods project
  - Adding frameworks to Pods project
  - Adding libraries to Pods project
  - Adding resources to Pods project
  - Linking headers
  - Installing targets
    - Installing target `AFNetworking` iOS 7.0
    - Installing target `Pods-testTaggedPointer` iOS 8.0
  - Running post install hooks
  - Writing Xcode project file to `Pods/Pods.xcodeproj`
    - Generating deterministic UUIDs
  - Writing Lockfile in `Podfile.lock`
  - Writing Manifest in `Pods/Manifest.lock`

主要做了:

  1. 生成Pods.xcodeproj工程:检测到改动,就更新Pods.xcodeproj;如果Pods.xcodeproj不存在,默认配置生成
  2. 将依赖中的文件/依赖库/资源加入工程:
  3. 设置目标依赖(Target Dependencies)
    1. 不只是代码加入,还有另外的几个文件:(配置文件、编译所需的文件、资源写入文件、许可文件等)
      在这里插入图片描述
      1. 包含编译选项的xcconfig/同时拥有编译设置和CPS默认配置的私有xcconfig文件;编译所需prefix.pch文件;编译必须的dummy.m文件
      2. 如果源代码含有资源bundle,向app中添加bundle的方式将写入Pods-Resources.sh(该脚本会将所有三方库的resource文件copy到目标目录中)
        在这里插入图片描述
      3. markdown、plist为用户许可文件
  4. lockfile、manifest编写:写入到磁盘
  • Integrating(集成) client project:集成工程所需的target

    • 生成workspace,管理多个工程
  • (CocoaPods将所有依赖库都放到一个Pods的项目中,然后主项目依赖Pods项目,这样,源码管理工作从主项目移到Pods项目中。Pods项目,最终会编译成一个名为libPods.a的文件,主项目只需要依赖这个.a文件即可)


  • pod update --verbose
Update all pods
Updating local specs repositories
Analyzing dependencies
    - Inspecting targets to integrate
    - !!!=>Finding Podfile changes
    - Resolving dependencies of `Podfile`
    - Comparing resolved specification to the sandbox manifest
Downloading dependencies
Generating Pods project
Integrating client project

  • Updating local specs repositories
    • 细心的会发现pod install没有这个过程,pod update有!这一点在下文的讲pod install和update的过程中,会提到。主要跟底层实现的默认值有关

看点CocoaPods源码

简单的抽一些源码看一下

  • pod install的过程
    • 在CPS中,所有命令都会由Command类派发到对应的类,而真正执行pod install的类是Install
    • Install类-Installer实例-执行install!方法
  • Installer的实例方法install!就会使用这些信息安装当前工程的依赖:分4部分
def install!
  resolve_dependencies    // 解析Podfile中的依赖:会创建一个Analyzer类的实例
  download_dependencies   // 下载依赖
  generate_pods_project   // 创建 Pods.xcodeproj工程
  integrate_user_project  // 集成workspace
end

  1. resolve_dependencies
def resolve_dependencies
  analyzer = create_analyzer

  plugin_sources = run_source_provider_hooks
  analyzer.sources.insert(0, *plugin_sources)

  UI.section 'Updating local specs repositories' do
    analyzer.update_repositories
  end if repo_update?

  UI.section 'Analyzing dependencies' do
    analyze(analyzer)
    validate_build_configurations
    clean_sandbox
  end
end
  • 内部有一个Analyzer类
  • 看到if repo_update?,是否需要更新本地local spec文件有关
  • 同时,会对podfile中的依赖进行分析。内部采用Milinillo依赖关系的解决算法,算法核心是回溯及向前检查。最后会返回一个依赖图,CocoaPods拿到后,会在specs_by_target中按照target(一般工程都会有多个target)将所有的specification分组
  • specification包含当前工程依赖的三方库:名字、版本、源,用于依赖的下载

  1. download_dependencies
    我们经常会看到如下状态
-> Using AFNetworking (1.8.8)
-> Using AFNetworking (1.8.8) was (1.8.6)
-> Installing AFNetworking (1.8.8)
  • 不同的状态,调用不同的方法
    • create_pod_installer:只创建一个PodSourceInstaller实例,然后加入到pod_installers数组中,依赖的版本没变,无需重新下载
    • nstall_source_of_pod:调用栈非常庞大,在调用栈末端Downloader.download_Source会执行CocoaPods组件CocoaPods-Download,方法中调用的for_target会根据不同的源创建一个下载器,因为依赖可能会通过不同的协议/方式进行下载,如git/http/svn等,CocoaPods-Downloader会根据依赖的参数选项使用不同的方式下载
  • 大部分依赖会被下载到~/Library/Caches/CocoaPods/Pods/Release/ 文件夹中,然后从这里复制到项目工程目录下的./Pods中,完成了整个CPS的下载流程
    在这里插入图片描述

  1. generate_pods_project
def generate_pods_project(generator = create_generator)
  UI.section 'Generating Pods project' do
    generator.generate!
    @pods_project = generator.project
    run_podfile_post_install_hooks
    generator.write
    generator.share_development_pod_schemes
    write_lockfiles   ==>lockfile是在生成Pods.xcodeproj这一步产生的
  end
end

上面调用到了PodsProjectGenerator实例方法generate!

def generate!
  prepare
  install_file_references
  install_libraries
  set_target_dependencies
end
  • 主要做的事情:
    • 生成Pods.xcodeproj工程
    • 将依赖的文件、library加入工程
    • 设置目标依赖,target dependencies
  • 这些操作主要依赖CocoaPods/Xcodeproj组件,该组件负责所有工程文件的整合

  1. integrate_user_project:生成workspace,管理多个工程
  • UserProjectIntegrator类,调用integrate!,集成工程所需的target
def integrate!
  create_workspace
  integrate_user_targets
  warn_about_xcconfig_overrides
  save_projects
end
  • 生成workspace,获取需要集成的taget,调用他们的integrate(下面附了过程代码)(跟之前描述的一样,各种配置、资源拷贝、检查manifest),将target加入到工程,使用Xcodeproj修改copy Resource Script Phrase等设置,保存project.pbxproj,整个pod install过程结束
def integrate!
  UI.section(integration_message) do
    XCConfigIntegrator.integrate(target, native_targets)

    add_pods_library
    add_embed_frameworks_script_phase
    remove_embed_frameworks_script_phase_from_embedded_targets
    add_copy_resources_script_phase
    add_check_manifest_lock_script_phase
  end
end


Podfile.lock 和 Manifest.lock
  • 生成Pods.xcodeproj中有write_lockfiles这一步
  • 生成Pods.xcodeproj之前的大多工作是在内存中进行的,为了能让这些成果被重复利用,需要将结果所有结果保存到一个文件,Pods.xcodeproj文件被写入磁盘,另外生成两个重要的文件Podfile.lock,Mainfest.lock都被写入磁盘
    • Podfile.lock:记录每个需要被安装的pod的每个已安装的版本(查看安装的版本)。需要加入git版本控制
    • Manifest.lock:每次执行pod install时创建的Podfile.lock文件的副本。如果遇到The sandbox is not in sync with the Podfile.lock,沙盒文件与Podfile.lock文件不同步,就是因为这俩文件不一致引起。由于Pods所在的目录并不总在版本控制下,这样可以保证开发者运行app之前,都能更新他们的pods,否则app可能会crash,或者一些不太明显的地方编译失败
pod install 和 update的区别
  • Command类会派发给Install or Update类
module Pod
  class Command
    class Install < Command
      def run
        verify_podfile_exists!
        installer = installer_for_config
        installer.repo_update = repo_update?(:default => false)
        installer.update = false
        installer.install!
      end
    end
  end
end

module Pod
  class Command
    class Update < Command
      def run
        ...
        installer = installer_for_config
        installer.repo_update = repo_update?(:default => true)
        installer.update = true
        installer.install!
      end
    end
  end
end
  • 非常关键的,看内部的installer的实例对象的配置,一个repo_update,install默认值是false不更新podspec索引,update默认值是true。,这也是为什么上文在执行pod install --verbose的时候,没有Updating local specs repositories过程的原因
  • 同时还有一个update的属性,这一点我觉得应该是影响了后续的一些行为不一样的关键
  • 最大区别:
    • install默认不更新本地podspec索引,update默认会更新
    • install并不会修改Podfile.lock中显示指定的版本
      • 一般在添加/移除库,首次使用。对于.lock已存在的库,会下载明确的版本
      • 不会检查是否有新的版本。不在的,会找podfile描述的版本
      • 只会解决pods里但不在.lock里的库之间的依赖
    • update会无视已有的Podfile.lock文件,只要符合podfile的限制,重新对依赖进行分析,尝试将所有pod更新到最新版

常见的目录&指令

目录

  • ~/.cocoapods/repos
  • ~/Library/Caches/CocoaPods/Pods
  • 三方库在Pods目录下,同时还有Pods.xcodeproj,Manifest.lock
    在这里插入图片描述

指令

  • pod env:查看CPS版本
  • pod outdated:查看Podfile文件中的依赖库的最新版本
  • pod search xx:查找所有可用的库
  • pod update PODNAME:忽略.lock,只更新这个库的新版本。只要符合podfile的限制

参考:
https://guides.cocoapods.org/
https://mp.weixin.qq.com/s/VKGWwXpTfvVpYPh11DVSvg

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值