Pages

Thursday, August 11, 2016

Private CocoaPods - Practical Advise

| Intro |

Recently I was faced with a challenge of sharing a source code of a privately developed iOS app with a group of customers. In this app I used several helper pods which I found using the official CocoaPods search engine and also the pods which were developed privately. All privately developed pods were synchronized with a BitBucket repository and I didn't want to give every customer access to it.

As far as I can see, there are such options that could be used in this case:

  • Distribute the source code as is and ask the customers to reconfigure the project in accordance with their own private repository;
  • Give every customer read access to my private repository
  • Copy private pods into the main project folder and use the relative references in a podfile
  • Use some other mechanism instead of CocoaPods 

I wanted to make the process of app configuration for customers as simple as possible so I decided to avoid the first option and look for another ways which would fulfill all my requirements.

I could, of course, give every customer read access to my private repository but, obviously, this is not a very scalable and flexible solution. So after doing some research I have finally chosen the third option, i.e. distributing the private pods alongside the main source code folder and using the relative references.

I this blog post I want to describe the precise steps of private pods configuration. Also I would like to show you how to distribute the source code containing private pods which would require zero-configuration and how to associate your private pod with a private repository.

Private Repos

There are a lot of articles in the internet describing the benefits of using a version control system (VCS) for your project changes management. In short words, with the help of VCS it is possible to undo all the messed-up things you've made in a few clicks. I would like to quote Troy Hunt here to encourage you to use VCS (in case if you don't):
The only measure of progress is working code in source control. If it's not in source control, it doesn't exist.
Besides the flexibility that VCS gives you for free it also can act as a backup tool because:
  1. Every collaborator has a full-fledged project version saved on his disk (including the project's complete history)
  2. The full project package is also stored in the center repository (which should be created in the dedicated sever) 
Depending on your project type, you can choose, basically,  between two repository configurations:
  1. Private repository
  2. Public repository
Public repositories are viewed by anyone who has a computer with access to the internet. They are usually used for open-source projects, when you don't need to control access to the source code and just want to show the world your great work and, perhaps, to draw attention of the potential collaborators.

If your application is closed-source, the private repositories would be your preferred choice. By using the private repos you can protect you code from being stolen by some bad guys. Of course, it's possible to indicates in the license notes that the derivative works and commercial usage are not allowed. But it's up to you to find out whether your code is used legally or not. 

There are many services you can use to create either public or private repositories. Each service provider has different terms and conditions. 

For example, GitHub allows you to create unlimited number of public repos, but at the same time to make it possible to create a private repo you should have a paid account.

Personally, for all my closed-source apps I've chosen BitBucket service. You can read more about its pricing model here. What sets it above all other solutions is that it's completely free for small teams (up to 5 developers) and you can have unlimited number of public and private repositories.

Before continue to the next section you should have already configured the private repo containing your app's source code using the preferred service. For example, to configure a BitBucket private repo you should follow these instructions

Private Spec Repo

When you run the following command from the project main directory:

pod install

the CocoaPods installed on your system, first of all, scans this directory for the presence of podfile. If the podfile has been found it starts to analyze the instructions contained in this file which specify how to resolve all dependencies required by the current project.

As an example, the podfile could look like the next code snippet:

platform :ios, '8.0'
use_frameworks!

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

def common_pods
    pod 'XCGLogger', '~> 3.3'
    pod 'SVProgressHUD', '~> 2.0'
end

target 'YOUR_PROJECT_TARGET' do
    common_pods
 
    target 'YOUR_PROJECT_TEST_TARGET' do
      inherit! :search_paths

    end
end

As you can see, in the podfile we only indicate the required libraries names and the preferred versions. This file is, basically, just a declarative way used to describe what pods do you need for your app. But CocoaPods system also needs to know the exact instructions of how to integrate these pods with the Xcode project. Podspec files include exactly these details.

By default, as depicted in the previous code snippet, the podspec files are located in the CocoaPods public Spec repository. It is specified by this line:

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

So if your goal is to make all things to be private you should create your own private Spec repository. This can be an ordinary repository just like the one you have created in the previous section using BitBucket's tutorial (or instructions of your preferred service provider).

Don't push anything to the private Spec repository for now. You will use CocoaPods pod tool for this purpose in the next section.

What you should understand now is that all podspec files of your privately developed pods are hosted in your private Spec repository. And to correctly integrate private pods with your project the URL of this repo must be specified in the podfile like this:

source 'URL_TO_YOUR_PRIVATE_SPEC_REPO'

Note: You shouldn't be worried about the source lines order unless your pods are located in both repositories. In the last case CocoaPods will use the highest version of a Pod of the first source which includes the Pod.

Add Private Spec Repo to CocoaPods

To simplify the process of adding the podspec files to you private Spec repo you should firstly add this Spec repo to CocoaPods installed on your local machine. It can be done with the help of the following command:

pod repo add REPO_NAME SOURCE_URL

As a REPO_NAME you can use any name you want (for example, this can be "my-cool-pods-spec").

A SOURCE_URL must match the URL of the previusly configured private Spec repo.

It's worth noting that you can always check which Spec repos you have already added by using the next command:

cd ~/.cocoapods/repos/; ls

On my test machine this command gives the output that is depicted in the following image:

The output that shows all added Spec repos names

Push Podspec Files to Private Spec Repo

Now to push the podspec files of your privately developed pods to the private Spec repo all you need to do is to run the following command:

pod repo push REPO_NAME SPEC_NAME.podspec

REPO_NAME is a name of the previously added private Spec repo  to your local CocoaPods installation.

SPEC_NAME.podspec is a podspec file of some privately developed pod.

CocoaPods will automatically run all the required validation tests (like pod spec lint) and configure the remote private Spec repo without your intrusion.

Note: I assume that you already know how to create and configure the pod libraries. I can create another blog post regarding this subject. Please, let me know in the comments whether you need it.

This is all configuration that must be done for the development stage. But if also you want to distribute the source code to your customers and to make it possible for them to run your app just by double-clicking the PROJECT_NAME.xcworkspace file (without preliminary setup), please, read the next section.

Distribute Source Code to Customers

To simplify the process of source code configuration for your customers you can follow the next advices:
  • Before distributing the source code copy all the required private pods into the main project directory. Let's call it 'Private Pods'.
  • In your podfile add the relative references to each private pod used in the project. It can be done like this:
pod 'MyCoolPrivatePod', :path => './Private Pods/MyCoolPrivatePod'

Now when the customers run pod install command all required pods will be installed automatically without the need of the private repos configuration. Hence, the line with the source URL should be removed (or commented out) from your podfile as it is no longer required:

#source 'URL_TO_YOUR_PRIVATE_SPEC_REPO'

Also don't forget about the following edge cases:
  • Do not add Pods folder to .gitignore, this way your project could be compiled out of the box without the need to run pod install
  • It's fine to add Private Pods folder to .gitignore because every private pod should be already under the source control system
That's it. Thanks for your time. Hope this blog post will be helpful for you.

Used Software Versions

CocoaPods: 1.0.1
Xcode: 7.3.1