iOS开发工程化-cocoapods详解

iOS开发工程化-cocoapods详解 | HChong的博客地址 <body> 戳我 戳我 文章目录

本文主要讲解cocoapods的相关知识, 关于cocoapods的实践, 可以参考这里.

1 源码分析

pod的使用主要在 pod installpod update, 我们可以在cocoapods的1.7.5版本中查看入口的源码.

def install!
  prepare
  resolve_dependencies
  download_dependencies
  validate_targets
  generate_pods_project
  if installation_options.integrate_targets?
    integrate_user_project
  else
    UI.section 'Skipping User Project Integration'
  end
  perform_post_install_actions
end

分析源码可以发现, install的执行分为如下几个步骤: 准备阶段, 查找依赖库, 下载依赖文件, 检验target, 生成pod工程, 整合project文件, 执行安装后操作, 下面会逐步讲解一下.

1.1 准备阶段

def prepare
  # Raise if pwd is inside Pods
  if Dir.pwd.start_with?(sandbox.root.to_path)
    message = 'Command should be run from a directory outside Pods directory.'
    message << "nntCurrent directory is #{UI.path(Pathname.pwd)}n"
    raise Informative, message
  end
  UI.message 'Preparing' do
    deintegrate_if_different_major_version
    sandbox.prepare
    ensure_plugins_are_installed!
    run_plugins_pre_install_hooks
  end
end

我们可以看到, 准备阶段(prepare)主要做了以下事情:

  • 检查podfile.lock的写入的cocoapods版本和当前cocoapods版本是否一致,如果不一致将会重塑工程,将除了Podfile、Podfile.lock、Workspace以外的其他关联和依赖全部重置
  • 沙盒的准备 - 一些文件以及目录的删除以及创建
  • 迁移沙盒中部分文件(区分Pods版本迁移地址不同)
  • 确保Podfile指定的插件都已经安装(不然抛错)
  • 执行pre_install的Hook

1.2 查找依赖库

def resolve_dependencies
  plugin_sources = run_source_provider_hooks
  analyzer = create_analyzer(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
  end

  UI.section 'Verifying no changes' do
    verify_no_podfile_changes!
    verify_no_lockfile_changes!
  end if deployment?

  analyzer
end

我们可以看到, 查找依赖库(resolve_dependencies)主要做了以下事情:

  • 遍历注册的所有插件,其中通过HooksManager.register方法注册name为:source_provider的插件
  • 执行create_analyzer方法创建安装分析器
  • 如果我们在执行pod install时附加了–repo-updateflag, 则刚才创建的analyzer实例将执行update_repositories方法去更新本地repo仓库的所有pod spec文件.
  • 验证Build Configurations参数的有效性
  • 验证podfile的变化
  • 验证lockfile的变化

1.3 下载依赖文件

def download_dependencies
  UI.section 'Downloading dependencies' do
    install_pod_sources
    run_podfile_pre_install_hooks
    clean_pod_sources
  end
end

我们可以看到, 下载依赖文件(download_dependencies)主要做了以下事情:

  • 下载安装Pods依赖库源文件
  • 执行Podfile中pre_install钩子方法
  • 根据Config和Installers参数清理Pods的源文件

1.4 检验target

def validate_targets
  validator = Xcode::TargetValidator.new(aggregate_targets, pod_targets)
  validator.validate!
end

检验target(validate_targets), 主要做了以下事情:

  • 检测是否有多重引用 framework 或者 library 的情况(Framework的名字是否冲突, 如果冲突会抛出frameworks with conflicting names异常)
  • 处理静态库传递依赖问题(静态库的传递依赖如果形成会主动抛出transitive dependencies that include static binaries异常)
  • 校验不同 target 所引用的代码中, 如果包含 swift, 所使用的 swift 版本是否相同
  • 检查是否引用了Switf书写的framework(Podfile中没有指定use framework!。如果验证不通过, 主动抛出异常)

1.5 生成Pods工程

def generate_pods_project
  stage_sandbox(sandbox, pod_targets)

  cache_analysis_result = analyze_project_cache
  pod_targets_to_generate = cache_analysis_result.pod_targets_to_generate
  aggregate_targets_to_generate = cache_analysis_result.aggregate_targets_to_generate

  clean_sandbox(pod_targets_to_generate)

  create_and_save_projects(pod_targets_to_generate, aggregate_targets_to_generate,
                           cache_analysis_result.build_configurations, cache_analysis_result.project_object_version)
  SandboxDirCleaner.new(sandbox, pod_targets, aggregate_targets).clean!

  update_project_cache(cache_analysis_result, target_installation_results)
  write_lockfiles
end

生成Pods工程(generate_pods_project), 主要做了:

  • 调用Podfile中post_install钩子方法
  • 生成Pods/目录下面的所有工程
  • 生成Podfile.lock文件和Manifest.lock文件

1.6 整合project文件

def integrate_user_project
  UI.section "Integrating client #{'project'.pluralize(aggregate_targets.map(&:user_project_path).uniq.count)}" do
    installation_root = config.installation_root
    integrator = UserProjectIntegrator.new(podfile, sandbox, installation_root, aggregate_targets, generated_aggregate_targets,
                                           :use_input_output_paths => !installation_options.disable_input_output_paths?)
    integrator.integrate!
  end
end

整合project文件(integrate_user_project), 主要做了:

  • 创建.xcworkspace文件
  • 集成Target
  • 警告检查
  • 保存.xcworkspace文件到目录

1.7 执行安装后操作

def perform_post_install_actions
  run_plugins_post_install_hooks
  warn_for_deprecations
  warn_for_installed_script_phases
  print_post_install_message
end

执行安装后操作(perform_post_install_actions), 主要做了以下操作:

  • unLock Pods库下的文件
  • 调用plugin的post_install钩子方法
  • 打印所有被废弃的pods警告信息
  • 打印所有pods中脚本的警告信息
  • 打印install中的所有信息

1.8 总结

  • 准备阶段
    • 检查podfile.lock的写入的cocoapods版本和当前cocoapods版本是否一致,如果不一致将会重塑工程,将除了Podfile、Podfile.lock、Workspace以外的其他关联和依赖全部重置
    • 沙盒的准备 - 一些文件以及目录的删除以及创建
    • 迁移沙盒中部分文件(区分Pods版本迁移地址不同)
    • 确保Podfile指定的插件都已经安装(不然抛错)
    • 执行pre_install的Hook
  • 查找依赖库
    • 遍历注册的所有插件,其中通过HooksManager.register方法注册name为:source_provider的插件
    • 执行create_analyzer方法创建安装分析器
    • 如果我们在执行pod install时附加了–repo-updateflag, 则刚才创建的analyzer实例将执行update_repositories方法去更新本地repo仓库的所有pod spec文件.
    • 验证Build Configurations参数的有效性
    • 验证podfile的变化
    • 验证lockfile的变化
  • 下载依赖文件
    • 下载安装Pods依赖库源文件
    • 执行Podfile中pre_install钩子方法
    • 根据Config和Installers参数清理Pods的源文件*
  • 检验target
    • 检测是否有多重引用 framework 或者 library 的情况(Framework的名字是否冲突, 如果冲突会抛出frameworks with conflicting names异常)
    • 处理静态库传递依赖问题(静态库的传递依赖如果形成会主动抛出transitive dependencies that include static binaries异常)
    • 校验不同 target 所引用的代码中, 如果包含 swift, 所使用的 swift 版本是否相同
    • 检查是否引用了Switf书写的framework(Podfile中没有指定use framework!。如果验证不通过, 主动抛出异常)
  • 生成pod工程
    • 调用Podfile中post_install钩子方法
      • 生成Pods/目录下面的所有工程
      • 生成Podfile.lock文件和Manifest.lock文件
  • 整合project文件
    • 创建.xcworkspace文件
    • 集成Target
    • 警告检查
    • 保存.xcworkspace文件到目录
  • 执行安装后操作
    • unLock Pods库下的文件
    • 调用plugin的post_install钩子方法
    • 打印所有被废弃的pods警告信息
    • 打印所有pods中脚本的警告信息
    • 打印install中的所有信息

2 实践 & 私有Pod

可以参考之前的总结

3 二进制方案

这里

这里是业界比较完善的解决方案

  • 主要的思路就是在创建pod的时候会同时存在源码和framework两种形态的包(可以通过新建target或者新建工程两种方式)
  • 在podspec中根据传入的参数来指定如何在源码和二进制中切换.

4 常见问题


参考资料:
1.CocoaPods 都做了什么?
2.Cocoapods源码浅谈
3.pod install和pod update背后那点事
4.cocoapods源码
5.Cocoapods 二进制
6.基于 CocoaPods 的组件二进制化实践
7.iOS CocoaPods组件平滑二进制化解决方案
8.iOS CocoaPods组件平滑二进制化解决方案及详细教程二之subspecs篇

关闭
上一篇:汇编语言之歌


下一篇:k8s一些基本命令