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
.
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:
- You want to collect stats about dependencies in the project (how many dependencies including transitive ones, how many vendor frameworks…)
- You want to enforce some rules for dependencies. For example, testing pods should not be imported to the main target.
- You write a tool for Bazel adoption that generates BUILD files based on a CocoaPods-based project.
- You want to alter CocoaPods behaviors. For example, turning pods into static frameworks by default.
- …
For upcoming explanations for CocoaPods, stay tuned!