CocoaPods

CocoaPods is a dependency management solution for iOS and Mac development, which uses a Ruby program to integrate third party code into your project.

Installing The Ruby Gem

El Capitan (Rootless)

El Capitan, by default, will not allow root access to anyone. Worse yet, Ruby 2.3.x is currently NOT compatible with CocoaPods! Here are instructions on how to set up a non-root, compatible instance of Ruby and CocoaPods along with it. (Based on instructions from Go Rails)

First, install Homebrew. This can be done by entering ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" into a terminal window. Enter your administrator password when prompted.

Next, you're going to install Ruby 2.2.3 via rbenv. First, use Homebrew to install rbenv and the ruby-build plugin by opening a terminal and running brew install rbenv ruby-build. Next, make sure rbenv loads each time you load a terminal with the following commands:

echo 'if which rbenv > /dev/null; then eval "$(rbenv init -)"; fi' >> ~/.bash_profile
source ~/.bash_profile

Lastly, install Ruby 2.2.3 and set it to be the default version of Ruby with these commands:

rbenv install 2.2.3
rbenv global 2.2.3

Verify that you are running Ruby 2.2.3 by using the command ruby -v. You should see something like

ruby 2.2.3p173 (2015-08-18 revision 51636) [x86_64-darwin15]

as the output.

Now that you have a working instance of Ruby, run gem install cocoapods (no sudo needed) and everything should hopefully go smoothly.

Yosemite and Before

You should already have a version of Ruby compatible with CocoaPods installed with OSX. Fire up your terminal and type in:

sudo gem install cocoapods (note that you may not need sudo)

Ruby will then install the CocoaPods gem, and you can then use CocoaPods on your computer.

NOTE: If you're using RVM or something similar to maintain multiple versions of Ruby and/or multiple gemsets, installation in a way that works completely may require more fiddling. Also, you're entirely on your own for that—we're iOSers, not Rails devs.

Further Information

Your first Podfile

Your Podfile should have a line like

source 'https://github.com/CocoaPods/Specs.git'

at the top, indicating that pods should be sourced from https://github.com/CocoaPods/Specs, the master (public) podspec repo. If it doesn't, please add such a line. (Note: the source directive was added in CocoaPods 0.34—if you are having issues, make sure you are running version 0.34 or later.) If you are planning to use anything in Vokal's private podspec repo, you should add it as a source above the master podspec repo, so that you have

source 'https://github.com/vokal/PrivatePodspecRepo-iOS.git'
source 'https://github.com/CocoaPods/Specs.git'

at the top of your Podfile.

Using a Project With CocoaPods

Because of the way CocoaPods works with projects, you should make sure that you are always opening the .xcworkspace file of your CocoaPods project, not the .xcodeproj (which will not be able to see the libraries brought in by CocoaPods).

Adding A Library Pod

CocoaPods uses a plain-text file known as a Podfile in order to manage what dependencies and which versions of those dependencies are used in your project.

To add your very first Pod to a project, create an empty plaintext document and name it Podfile, and place it in the same directory as your .xcodeproj file.

To add a Pod to an existing Podfile, you simply add a line with the name of the Pod and the version to which it is pointing.

pod 'AFNetworking', '~> 1.0'

Note that if you do not already know the appropriate version of the Library, you can use the pod search command to view available public Pods and their versions.

For example,

pod search vokoder

will search case-insensitively and return

-> Vokoder (1.0.11)
   Vokal's Core Data Manager
   pod 'Vokoder', '~> 1.0.11'
   - Homepage: https://github.com/vokal/Vokoder
   - Source:   https://github.com/vokal/Vokoder.git
   - Versions: 1.0.11, 1.0.9, 1.0.0 [master repo]

and you can just copy the pod 'Vokoder', '~> 1.0.11' line into your Podfile if you wish to use the current version.

Once the line adding the Library to your list of Pods has been added to the Podfile, go to the command line, CD into the directory where your Podfile lives, and run pod install. CocoaPods will go out and get the Pod and install it so you can use it in your project.

Note that you can also specify Pods which should only be included in a particular target. An example of this setup where the specified pods are only included in the test target:

target :NextTierTests, :exclusive => true do
  pod 'ILGAsserts', '~> 1.0'
  pod 'VOKMockUrlProtocol', '~> 1.0'
end

There are two types of libraries you can add to a Podfile: A library which already has a podspec set up, and one which does not.

For A Public Library Which Already Has A podspec

When adding a CocoaPod which already has a podspec (and therefore also has a versioning scheme), you must specify a version. You can either specify a version explicitly, by stating exactly which version of a library you wish to use, or "optimistically", by using the ~ operator.

All CocoaPods are supposed to use Semantic Versioning to distinguish between major, minor, and patch releases, but not all Pods make this distinction appropriately. Make sure you take a look at how big the updates typically are to a pod before choosing which version to use.

While you should generally keep your Library Pods pointed at their original repos, you should always make sure to speak to a Senior developer to get a Vokal fork created for third-party projects.

This protects us from Libraries that the original creator might have taken offline. It also allows us to integrate fixes on our end before they are merged into the main repository of the Library.

Note that for Libraries pointing at a public Vokal fork, you must make sure to point the Pod at our GitHub repo by using the :git parameter. Note that you can't specify a version when using the :git parameter, but you can point the Pod at a particular tag:

pod 'SFHFKeychainUtils-ARC', :git => 'https://github.com/vokal/SFHFKeychainUtils.git', :tag => '2.3.1'

Further information:

Creating a podspec for a library which does not already have one

If a library does not already have a podspec file, you will need to create a local podspec file and commit it to your repo.

Create a [LibraryName].podspec file, and add it to the same directory as your Podfile. Make sure you add this file to version control.

Here is an example of a podspec file pointed at a particular commit for a private repo (note that the deployment_target should match the deployment target for the library):

Pod::Spec.new do |spec|
  spec.name                   = 'VOKKeychainUserCreds'
  spec.summary                = 'Easy keychain access wrapping'
  spec.version                = '0.0.1'
  spec.platform               = :ios
  spec.ios.deployment_target  = '6.0'
  spec.authors                = {'Ellen Shapiro' => 'ellen.shapiro@vokal.io'}
  spec.homepage               = 'https://github.com/vokal/iOS-Keychain-User-Creds'
  spec.license                = 'Copyright 2014 Vokal'
  spec.source                 = {:git => 'https://github.com/vokal/iOS-Keychain-User-Creds.git', :commit => 'dce6d53fba'}
  spec.source_files           = 'VOKKeychainUserCreds/Library/*.{h,m}', 'VOKKeychainUserCreds/Library/SFHFKeychainUtils/*.{h,m}'
  spec.requires_arc           = true
end

Then, to access the file and have CocoaPods pull in your specified dependency, add a line like this to your Podfile, pointing at the podspec you created:

pod 'VOKKeychainUserCreds', :podspec => 'VOKKeychainUserCreds.podspec'

When you run pod install or pod update, this will install/update the unspec'd Pod in the same fashion as standard Pods.

Note: If you're making a podspec file for a public repo which does not already have one, you should open a pull request to the original repo with the podspec as a courtesy to its author. If the upstream repo is not responsive in merging in the podspec, it can be added to our private podspec repo.

Always Commit Your Pods!

One note on how we use CocoaPods a little differently from their traditional methodology here at Vokal: We always commit the contents of all Pods to a project repo.

This has several benefits for a team with many members like ours:

  1. Any new member of the team can pull a version of the project that will build and run at any time, even if they do not have the CocoaPods Ruby gem installed.
  2. Prevents version conflicts when one person has updated their pods but another hasn't.
  3. If the original Pod is removed by its author for some reason, we still have access to the code.
  4. We can ensure that our build server is always pointed at the exact code the team is using to build the project.

NOTE: Do NOT commit any changes you make yourself to any of the files in a CocoaPod to the main repo - these will get overwritten the next time someone runs pod install or pod update.

Updating Pods

Whenever you run pod install or pod update, make sure that you commit any changes that CocoaPods has pulled in, and make sure that you fix any errors introduced by those changes.

Remember: The goal of our setup is to always keep the project in a buildable state.

Caching credentials

Because CocoaPods uses HTTPS to access GitHub, it won't make use of your SSH key in order to access the private repositories used for our internal private podspecs. This means you'll be prompted for your username and password each time you pod install or update. GitHub has instructions to enable credential caching so that your creds will be stored (securely in the Keychain, for Mac users) so that you aren't prompted every time.

Creating a CocoaPod

Use Your Loaf created an excellent guide to creating a CocoaPod, complete with information about how to construct your podspec. For now, that should be considered the best guide to creating a podspec.

When creating a new private library, make sure that you create a podspec file and add it to our private podspec repo so that other members of the team can use your repo without having to rewrite the podspec themselves. Instructions on adding the podspec to our private podspec repo are here.

When creating a new public library, have a Senior engineer register it for Trunk so that updates can easily be pushed out. If you push the pod to Trunk yourself, please add the senior engineers as owners. In addition, make sure to ask the Senior engineer approving your updates to tag the release appropriately and push the podspec update up to the CocoaPods Trunk.

Further reading: