CocoaPods Best Practices

CocoaPods is a relatively new way to manage Xcode library dependencies like the Facebook iOS SDK et al. If you are coming from the Ruby world you know this kind of workflow from bundler. CocoaPods can be easily installed as a gem via ‘gem install cocoapods’ but this is where the pain begins. What if one developer is using CocoaPods 0.14.0 and another developer is using CocoaPods 0.16.0? To ease that problem we are using CocoaPods together with bundler.

Always use the same version of CocoaPods

We have a Gemfile where we exactly specify the CocoPods version we want to use:

bashsource 'http://rubygems.org'
gem 'cocoapods', '0.16.0'

So we never use a globally installed version of CocoaPods but a version that can be executed via bundler: bundle exec pod install

Always specify the version of a pod

When we started using CocoaPods we simple added our dependencies and let CocoaPods take care of the versions by locking them in the file Podfile.lock:

bashpod 'Facebook-iOS-SDK'
pod 'SBJson'
pod 'TestFlightSDK'
pod 'GoogleAnalytics-iOS-SDK'
...

But we soon found out that if you updated a specific version, things sometimes tend to break. In our case Google decided to break a header file in version 2.0beta3 of their Google Analytics SDK. Version 2.0beta4 fixes that problem, but if you just run “bundle exec pod update’ it not just updates a specific dependency - it updates all the pods. One of those pods broke our build chain. If you archived our project in Xcode it started to generate a Generic Xcode Archive instead of an iOS App Archive. We did not suspect that CocoaPods is the problem in the first place and Googled that problem for hours. “Skip install’ had the correct value and everything seemed to look fine. Then we started to work with an old Podfile again and everything was ok. So here comes the fix: we created a new Podfile and manually added all versions. After that, we just upgraded Google Analytics to the latest version.

bashpod 'Facebook-iOS-SDK', '3.1.1'
pod 'SBJson', '3.1.1'
pod 'TestFlightSDK', '1.2.beta2'
pod 'GoogleAnalytics-iOS-SDK', '2.0beta4'
...

And the problem was gone. So a best practice for us became to concretely add the version numbers for each pod so that we control the update mechanism.

Specify the version of your Ruby

That brings us to our last best practice. Since we are doing a lot of Ruby on Rails consulting we need to switch between different Ruby versions a lot and we use rbenv to control these environments. We wanted to apply the same control in our Xcode projects, so we specify the Ruby version in an .rbenv-version file:

1.9.3-p327

Always check in the Pods directory

Since there is no global repository for CocoaPods every maintainer of a library is responsible for keeping his versions online - which has actually gone wrong in the past. Some versions disappear or repositories are temporarily offline. So check in the Pods directory in your version control guarantees that you can reconstruct a specific version at any time. Also you don’t have to tell your designer friends how to install CocoaPods.

Through all that practices we can guarantee that a new developer is always getting the same environment for development without surprises. Hopefully CocoaPods will add the feature to update a specific pod in the near future. If you want to see the efforts of our latest app then download our social video player Watchlater (deprecated).

Cofounder of 9elements. Software alchemist since he was a kid. Knee deep in tech with building things in React, Rails or Solidity.

Let's talk about