Cocoapods Explained: Plugins

In the previous post, we talked about Podfile. In this post, we will look into CocoaPods plugins.

Back in early days, very few maintainers maintain quite some features. It was difficult for them to stick to the main goals of the project given a number of features being requested. Some features definitely benefit a group of users but they don’t quite fit in the picture of a dependency manager.

Instead of rejecting them, CocoaPods provided the support for plugins. With the plugin architecture, one can extend CocoaPods usage on their own. This helps not only ease the burden on the maintainers but also gives more freedom to community.

What is a CocoaPods plugin?

A plugin is a just a ruby gem having a file cocoapods_plugin.rb in its gem’s lib directory. This file is loaded when running any pod command such as pod install or pod --help.

For example, cocoapods-search is a CocoaPods plugin to search multiple pod spec repos for specific pods matching a query. Its directory is as follows:

--- lib --- cocoapods-search ---
       |--- cocoapods-search.rb
       |--- cocoapods_plugin.rb     # <-- HERE

This cocoapods_plugin.rb file is the entrypoint to load the actual implementation of the plugin. Therefore, most of the time you will see the content just like this:

require "cocoapods-search/command" # <-- Actual implementation resides in cocoapods-search/command.rb

To list the installed plugins, you can run pod plugins installed.

Figure 1. Listing installed plugins

Figure 1. Listing installed plugins

With a normal gem (ex. xcodeproj), you can magically turn it into a plugin by creating a cocoapods_plugin.rb file under its lib directory. Then, this gem should appear in the console when listing the installed plugins.

# Create a file in /Users/thuyen/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/xcodeproj-1.22.0/lib/cocoapods_plugin.rb
$ touch $(dirname $(gem which xcodeproj))/cocoapods_plugin.rb

$ pod plugins installed

Installed CocoaPods Plugins:
    - cocoapods-deintegrate    : 1.0.5
    - cocoapods-plugins        : 1.0.0
    - cocoapods-search         : 1.0.1
    - cocoapods-trunk          : 1.6.0
    - cocoapods-try            : 1.2.0
    - cocoapods-xcconfig-hooks : 0.0.1 (post_install hook)
    - slather                  : 2.7.2 (post_install hook)
    - xcodeproj                : 1.22.0     # <--- 👈 👈 👈

What can a CocoaPods plugin do?

First, you can tweak CocoaPods’s implementation. In the previous post, we mentioned the tweak in order to add the :xcode_migration option to the pod declaration. You can place the tweak in the plugin code instead.

Second, you can add new commands to the pod command. This is done by subclassing the Pod::Command class. For example, the following code allows the usage of pod analyze.

module Pod
  class Command
    class Analyze < Command # <-- Corresponding to the new command: pod analyze
      self.summary = "Analyze dependencies"

      def run
        # <-- Implementation goes here
      end
    end
  end
end

Finally, a plugin can hook into the pod installation process via pre_install/post_install hooks. A hook is registered using the Pod::HooksManager.register method.

# In cocoapods_plugin.rb

Pod::HooksManager.register("<gem_name>", :post_install) do |installer|
  # <-- Implementation goes here
end

Such plugin hooks are similar to the hooks declared in Podfile using pre_install/post_install methods. However, they are slightly different in terms of execution order and scope. We’ll cover more of this matter in another post about pod installation.

As you can see in figure 1, cocoapods-xcconfig-hooks and slather are shipped with the hooks. However, a plugin’s hook can only be executed if that plugin is declared in Podfile as follows.

# In Podfile
plugin "cocoapods-xcconfigs-hooks"

Note that this plugin method only affects the registered hooks. The plugin code is always loaded regardless of whether this method is called or not.

How to create a plugin?

Working with CocoaPods plugins is just like working with gems. Just take a glance at the guides at https://guides.rubygems.org during development. While writing plugin code, you might want to reference to cocoapods’s rubydoc and cocoapods-core’s rubydoc.

There are many CLIs that help create a gem at hand, for example, bundle gem cocoapods-foo or pod plugins create foo. Then, you just need to fill in some metadata.

Engineers sometimes place the gem code in the same project with iOS code for convenience. However, not all project contributors understand gem folder structure. They might get distracted by a scatter of non-iOS files even when only one of those files is of interest. In that case, you might consider using cocoapods-ezplugin without caring much about versioning, gemspec, and so forth.

When to consider writing a plugin?

Following are some examples:

For upcoming explanations for CocoaPods, stay tuned!