Using Cocoapods in Large Scale Apps

Using Cocoapods in Large Scale Apps

We love using CocoaPods to manage dependencies in all our iOS projects, it enables us to create a project and start working in literally few minutes!

However I started having some hard times keeping my iOS projects in sync with what the amazing Swift community is doing, not only the language is changing fast, but projects as well, new projects are born and old ones are being refactored and replaced quickly.

In this tutorial, I’ll explain a suggested workflow for managing 3rd party dependencies and how to make the Podfile, well, a little bit more interesting 😉

Let’s assume that we’re working on version 1.0.0 of a project that has the codename Apollo

A codename is a something we use at my company to identify our project publicly while in development without disclosing much information about them.

Semantic Versioning is what we use for versioning.

Let's also assume that the following dependencies have to be used to build the project

For each project from the dependencies above:

  1. Fork the dependency to our GitHub organization account
    • If the project is already forked, make sure to sync the fork with upstream to get the latest updates before proceeding, more here.
  2. Create a new branch — from wherever the current stable release is — with the name {codename}-{version}, for our example it will be apollo-1.0.0
  3. Use the following template to add dependencies to our Podfile:

ruby

platform :ios, '9.0' # Global variables REPO = 'https://github.com/GITHUB_ORGANIZATION_NAME' BRANCH = 'CODENAME-VERSION' target 'TARGET_NAME' do use_frameworks! ## Dependencies pod 'LIBRARY_1', git: "#{REPO}/LIBRARY_1", branch: "#{BRANCH}" pod 'LIBRARY_2', git: "#{REPO}/LIBRARY_2", branch: "#{BRANCH}" # ... end

For our example:

ruby

platform :ios, '9.0' REPO = 'https://github.com/GITHUB_ORGANIZATION_NAME' BRANCH = 'apollo-1.0.0' target 'Apollo' do use_frameworks! pod 'RxSwift', git: "#{REPO}/RxSwift", branch: "#{BRANCH}" pod 'Moya', git: "#{REPO}/Moya", branch: "#{BRANCH}" pod 'Kingfisher', git: "#{REPO}/Kingfisher", branch: "#{BRANCH}" end

Benefits

  • Have all 3rd party dependencies versions used in a specific version of our app is now grouped by a single keyword, say it is 1 year later, the current version for project Apollo is 4.3.0 and we want to debug something in version 1.7.0, all we have to do is just update the version number in Podfile, and perform a quick pod update.
  • We own a copy of any open-source dependency we use, if the maintainer decided to shutdown the project, well, at least we have more time to evaluate other options, or if it is important enough, maybe continue developing our fork.
  • Cherry-picking code from a dependency becomes as easy as creating a branch and update the code to keep only what we need, and remove what we don’t.
  • Fix bugs faster than dependencies maintainers sometimes.
  • Hopefully this will help other developers in our team to contribute back as soon as they fix any bug, We’re not sure, let’s see how this will go for a while :)

We’re now working on a script to update our forks, create new branches, update the Podfile and automate the whole process.

If you have any questions or suggestions, don’t hesitate to reach out to me on Twitter.