CocoaPods: Working With Internal Pods Without Hassle
I was one of the first supporters back in 2012 and I have some Pods in the Specs repo (ADB prefixed). Recently, I spent several days going through some hidden aspects of CocoaPods, ending up reading some source code from the Core and Xcodeproj.
During one of the last few NSLondon(s) of 2013, Orta explained the advantages of CocoaPods and Abizer Nasir, in the following meetup, discussed the usage of Git submodules. Basically comparing their visions.
What I’m going to explain here is a solution to a common scenario:
Manage the versioning of internal private pods within projects without hassle.
Ok, let’s start. You have your project under our DVCS (which I hope is Git for your sanity).
1 2 3 4
You use some third-party components like AFNetworking and MagicalRecords and you have submodules for that, you little nasty hipster!
1 2 3 4 5 6 7 8 9
You decide to use CocoaPods, install it following the instructions and you add the
1 2 3 4
You remove the submodules and run
pod install: the workspace is created for you and you’re good to go. So far so good.
1 2 3 4 5 6 7 8 9 10
Then you realize that it’d be cool to have your own private repo of pods and create private pods for some parts of your project. You like modular things and maybe, one day your pods will be ready for a pull request to the Specs repo to contribute to the open source community.
So you create your own repo (mine is https://github.com/albertodebortoli/ADBCocoaPodsRepository) and add it to CocoaPods.
Time to create a spec for your private pod, tag it and push it. Something like this:
1 2 3 4 5 6 7 8 9 10 11 12
pod install and the situation is as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
You want to put the
Pods folder in the
Cool! But… there’s a but. You’re actively developing on
MyInternalLibrary, you’re touching those files several times a day. The files you’re touching will be overwritten the next time you run
pod install. Oh shit. You don’t wanna open
~/MyInternalLibrary, touch things,
~/MyProject over and over. It’s not practicable.
Solution is: become friend of the development pods. When you install a development pod, its files are symbolically linked within
Podfile, now, specifies that the pod needs to be fetched from a local directory (with the use of the
:path directive). A development pod does not require to be versioned with a Git repo, but it must contain the podspec which describes how to retrieve the pod files. This is your new
1 2 3 4 5
That’s great, now you can touch things safely and you can commit changes to
~/MyInternalLibrary) while you are working on
Here comes the interesting bit.
You have a CI and deployment system that need to have a specific version of your internal pod. You are tempted to tag changes to
MyInternalLibrary when deploying and use a specific
Podfile in your release branch of
1 2 3 4 5
Yeah… yeah… you’re cool.
No, you’re not.
Do you see the problem here? Keep the versioning/tagging of the internal pods updated is a pain in the ass. Developer’s time should never be wasted this way.
I see you thinking…
"Damn, pods are not quite right here. I'm a hipster and a submodule would be perfect! But ufff... submodules or CocoaPods? Uff uff...".
The answer is… use both! Is the versioning/tagging of your library (just for accommodating CocoaPods) complex? Well, let the submodules handle it for you (using the
sha1 of the commit, you know… Git things to point to the correct revision).
The ideal solution is to put your internal library inside the folder of the project and treat it as a git submodule:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Podfile will be
1 2 3 4 5
pod install, files in
~/MyProject/MyInternalLibrary will be symbolically linked within
Now you can
- work on your project and change your libraries/pods while developing
- commit changes to your libraries/pods independently of your project
- tag/version your internal libraries/pods when you want to (not when it is requested by your project)
- avoid the need of a specific Podfile for the release branch on MyProject
People way too often want to embrace CocoaPods fully, others prefer just submodules (and they are wrong, period). I think that the pragmatic solution to edge cases like this one is to use both!
Work as if it was just a submodule but with the unleashed power of CocoaPods!