cocoapods Hook 和 Plugin

1,491 阅读2分钟

在使用cocoapods的时候,如果有需要在某些生命周期中做自定义操作,cocoapods提供几个周期节点供开发者Hook。

hook简介
pre_installPod下载之后但在安装之前对Pod进⾏任何更改
pre_integrate将⽣成的Xcode项⽬写⼊磁盘之前
post_install⽣成的 Xcode 项⽬写⼊磁盘之前对其进⾏任何最后更改
post_integrate在项⽬写⼊磁盘后进⾏更改

而Hook的方式有2种:在podfile中直接Hook,或者通过cocoaposd plugin的方式Hook。

Podfile Hook

在podfile中添加如下代码:

pre_install do |installer|
  puts "pre install hook"
end

post_install do |installer|
  puts "post install hook"
end

这时候调用pod install命令:

image.png

可以看到我们自定义的打印已经输出。

使用pod update 同样可以触发 image.png

在podfile中hook的这种方式比较方便,如果有有一些标准化的流程需要执行,可以考虑制作cocoapods plugin的方式。

Plugin Hook

我们可以通过创建Gem三方库的方式。使用命令bundle gem cocoapods-hello-plugin

image.png 现在就已经创建好了一个Gem三方库。我们可以使用编译软件打开(这里我用的是VSCode)。

ocoapods_plugin.rb

建立完工程,需要手动创建cocoapods_plugin.rb文件,必须在lib目录下。其作用是cocoapods和plugin之间的联系纽带。

module Pod

# hook

    @HooksManager = HooksManager

    @HooksManager.register('${项目名}', :post_install) do |_, _options|

    print('333')

    end
end

这里类似OC的方法交换,可以理解为将代码print插入到 pod install 命令当中。其作用和PodFile中的hook作用是一样的。

rake install

rake install:local
使用该命令可以将正在开发的ruby项目部署到本地,从而达到测试和调试的效果。

image.png 这里需要注意,必须本地安装过rake才可以使用,可以使用gem info rake查看是否安装过rake

image.png

如果没有安装过rake,可以使用命令gem install rake 来安装rake。

另外rake install:local命令中务必注意install 和 local中间没有空格,如果有空格也会有错误。

image.png

安装成功后,在使用pod install命令就会出现在plugin的打印内容了:

image.png

如果在不需要的时候,记得使用gem uninstall xxx 来卸载该库。

image.png

Plugin 加载原理

在cocoapods执行命令的时候,需要提前去价值cocoapods的所有插件,其查找插件的规则如下: 在本地所有的gem库中查找,是否存在cocoapod_plugin.rb的文件,如果存在,记录下这个路径。最后统一去执行。其中部分源码如下:

      # @return [Array<Gem::Specification>] Loads plugins via RubyGems looking
      #         for files named after the `PLUGIN_PREFIX_plugin` and returns the
      #         specifications of the gems loaded successfully.
      #         Plugins are required safely.
      #
       # 加载插件
      def self.load_plugins(plugin_prefix)
        loaded_plugins[plugin_prefix] ||=
          plugin_gems_for_prefix(plugin_prefix).map do |spec, paths|
            #通过本地path来加载需要加载的库
            spec if safe_require(paths)
          end.compact
      end
      # @return [Array<[Gem::Specification, Array<String>]>]
      #         Returns an array of tuples containing the specifications and
      #         plugin files to require for a given plugin prefix.
      #
      def self.plugin_gems_for_prefix(prefix)
        # glob = cocoapods_plugin.rb
        glob = "#{prefix}_plugin#{Gem.suffix_pattern}"
        # 遍历本地所有的gem库,如果里面能匹配到 cocoapads_plugin
        Gem::Specification.latest_specs(true).map do |spec|
          matches = spec.matches_for_glob(glob)
          [spec, matches] unless matches.empty?
        end.compact
      end