Create your own CocoaPods library

Learn how to create a pod from scratch and utilize Travis and Codecov to make the pod robust.

Introduction

As an iOS developer, you may have used a few CocoaPods libraries in your project, and you may have been very familiar with how to install them and call their methods. However, have you ever dreamed of contributing to the iOS open-source community by distributing your own pod(CocoaPods library)? Imagine many iOS apps are going to use your awesome library, isn’t that fantastic?

In this tutorial, I will show you how to distribute a simple pod. In addition to that, you will also learn how to leverage Travis CI and Codecov to make sure your pod is reliable and robust.

Overview

There are many different ways to create a pod. The most common one is to follow CocoaPods official document Using Pod Lib Create, basically, you can use the following command to quickly bootstrap an Xcode workspace to develop a new pod:

> pod lib create [pod name]

In the bootstrapped workspace, one thing I don’t like is that the codes related to unit test are nested inside the example target, it doesn’t make sense to me. After some trial and error, I figured out a way to create a pod from scratch and nicely organize the codes for unit testing and examples.

Here is a quick overview of all the steps to create a pod:

  1. Set up Xcode project and necessary targets
  2. Link to Github
  3. Implement the pod
  4. Write unit tests
  5. Configure Travis CI and Codecov
  6. Publish the pod

At the time of writing, I am using the following Softwares:

  • macOS Mojave 10.14.3
  • Xcode 10.1
  • Swift 4.2
  • cocoapods 1.6.0

Ok, let’s get started!

Set up Xcode project and necessary targets

Actually, before we create the project, there’s an important task to do, let’s name our pod SwiftyLib and make sure the name has not been taken on CocoaPods, luckily it’s not been submitted, so we can go ahead.

Create a Cocoa Touch Framework Xcode project

Under the hood, a CocoaPods library is a Cocoa Touch framework library. Launch Xcode and create a new project, choose Cocoa Touch Framework .

Enter the name SwiftyLib , select the checkbox Include Unit Tests . On the next page select the project location and do not check Create Git repository on my Mac as we are going to create it later on.

After you hit the Create button, the project is created and the workspace should look like the following:

Prepare the targets

As you can see, we now have a project called SwiftyLib and it has two targets:

  1. SwiftyLib: Our pod implementation will happen in here
  2. SwiftyLibTests: Unit tests our pod and collects code coverage

In Xcode, each target has a scheme that allows you to control build and test behaviors. As you can see in the SwiftyLib scheme, when we perform the Test command, it will trigger the tests written in SwiftyLibTests target.

In many Cocoapods projects, developers like to put some demos or examples as part of their pods, those will help people better understand how to use the pods. To do that, let’s add a new target called SwiftyLibExamples . Select SwiftyLib project from the project navigator, then choose File > New > Target…, select Single View App as the template and click on Next .

Enter the name SwiftyLibExamples and click on Finish .

Now the project navigator should look like this:

The SwiftyLibTests is not nested inside the SwiftyLibExamples . Later we will implement the examples using our pod, for now, we just complete our first step and successfully scaffold the project for making a pod!

Link to Github

Needless to say, Github is the best hosting service for open-source projects, more importantly, when you publish the CocoaPods library, Cocoapods asks you to specify the location from where the source should be retrieved, and Github is a perfect choice.

Create a new repository

Go to Github and create a new project called SwiftyLib , keep other settings as default and click on Create repository , an empty Github repository is now created.

In the next screen, we are going to use the following information to link our existing Xcode project:

Link existing project

Open up a terminal, navigate to the SwiftyLib Xcode project folder, and type in the following commands:

> git init
> git remote add origin git@github.com:{USERNAME}/SwiftyLib.git
> git add .
> git commit -m "Initial project setup"
> git push -u origin master

README and MIT License

Now we have uploaded our source codes to Github! Before we finish this section, let’s create a README.md file and an MIT license file from the Github page. To create a README.md click on the Add a README button, to add an MIT license file, click on the Create new file button and follow Github’s official guide here, it’s really simple.

Once you are done, type in the following command to sync with the remote repository.

> git pull
...
2 files changed, 24 insertions(+)
create mode 100644 LICENSE
create mode 100644 README.md

Well done, you have just completed another milestone!

Implement the pod

It’s time to write some Swift codes and implement our SwiftyLib. As we mentioned earlier, all the implementation is going to happen in the SwiftyLib target. In the project navigator, right click on the SwiftyLab target and select New File...

Choose Swift File as the new file template, click on Next …

Name the file as SwiftyLib , make sure this file belongs to the SwiftyLib target and save it in the SwiftyLib folder as shown in the screenshot below.

Let’s edit the newly created SwiftyLib.swift file:

Our library is fairly simple! It has two functions to do the calculation. Save the file. Remember, whenever you edit files in the SwiftyLib target, in order to let other targets use them, don’t forget to build the SwiftyLib target! Click on the Build button or use the keyboard shortcut ⇧⌘R Shift-Command-R .

we just implemented our SwiftyLib library, let’s write some unit test cases.

Write unit tests

Unit testing is crucial for making sure your library is robust, and since our library is pretty simple, writing unit tests is easy :)

Edit theSwiftyLibTests.swift :

Here we only test the add() function. Run the unit test by clicking on the Test task 🔧:

The test case should be passed, switch to the reports navigator and check the code coverage:

As you can see, the coverage is only 50%, because we didn’t write a unit test for the sub() function, let’s do that now!

Now run the test again and our code coverage should be improved to 100%!

At this point, we have a pretty robust pod, let’s save all our changes and push them to Github.

> git add .
> git commit -m "Added test cases"
> git push

Configure Travis CI and Codecov

Whenever we push new changes to Github, we should test our pod and make sure all test cases are not broken.

Travis CI is a hosted, distributed continuous integration service used to build and test software projects hosted at GitHub.

We can leverage Travis to help us run test cases and submit the code coverage report to Codecov.

Codecov is a reporting tool that is intended to process any coverage report format into a format that is standard across Codecov. You may change the configuration of how Codecov processes reports and expresses coverage information.

In order to let Travis pick up any change in our Github repo, sync up your Github account on Travis and enable our SwiftyLib repository.

Create a .travis.yml file in our project folder:

Basically, it instructs Travis to run the unit tests on two different devices that run different iOS versions.

You can ask Travis to test on more devices, but make sure the version of iPhone simulator supports those devices, you can check the full list here.

Save the .travis.yml file and push it to Github, trigger a build on Travis, you should see that Travis runs the test cases for the commit you submitted.

Next, let’s ask Travis to send the code coverage report to Codecov. Before we go too far, let’s take a look and see what Travis has done so far. Travis executes the following script to run the test:

> xcodebuild test \
-enableCodeCoverage YES \
-project SwiftyLib.xcodeproj \
-scheme SwiftyLib \
-sdk $TEST_SDK \
-destination "platform=iOS Simulator,OS=$OS,name=$NAME" \
ONLY_ACTIVE_ARCH=YES

Notice that the code coverage report is generated with the xcodebuild test command. If we follow Codecov’s guide, we can simply push the code coverage report to Codecov with the commands below:

> bash <(curl -s https://codecov.io/bash) -t {CODECOV_TOKEN}

you probably will see some weird report with unnecessary files being reported, but we only want to see the coverage report like the one we saw earlier in Xcode.

Slather

To fix the problem, that is to let Travis send the accurate code coverage report to Codecov, let’s borrow another tool Slather. With slather, we can specify how to collect the code coverage information accurately.

First, let’s create the configuration file to define how to collect the code coverage information, create a new file called .slather.yml :

Here we tell slather to collect the code coverage information from SwiftyLib scheme and please ignore the codes from the unit tests.

Now edit .travis.yml and add an after_success section to upload the report that collected by slather to Codecov after the unit testing is completed.

If you take a look at the log from Travis, you will see that the reports are being collected by slather and sent to Codecov:

You can check the code coverage details on Codecov:

Excellent! We reached another milestone, our pod is robust and protected by Travis and Codecov.

Publish the pod

Finally, it’s time to publish our pod! First, install cocoapods .

> gem install cocoapods

Then create a podspec file that defines our pod, e.g., where to find the source.

> pod spec create SwiftyLib
...
Specification created at SwiftyLib.podspec

Edit the SwiftyLib.podspec file:

Check if SwiftyLib.podspec is correct, fix issues if there is any

> pod lib lint
...
-> SwiftyLib (0.0.1)
SwiftyLib passed validation.

Great! Let’s save our changes to Github!

> git add .
> git commit -m "Added SwiftyLib.podspec"
> git push

Start to distribute our library

Tag the correct version

> git tag 0.0.1
> git push origin 0.0.1

Then push it!

> pod trunk push
...
Updating spec repo `master`
---------------------------
🎉 Congrats
🚀 SwiftyLib (0.0.1) successfully published
📅 February 24th, 15:49
🌎 https://cocoapods.org/pods/SwiftyLib
👍 Tell your friends!
---------------------------

Notice that the version number should match the spec.version defined in the SwiftyLib.podspec .

Congratulations! You just published the CocoaPods library to the open-source community!

The project source code can be found in Github.