12 January 2016
Follow @ortaTLDR: CocoaPods now has a Mac App that provides a hosted Ruby experience, go check out the web page for it: cocoapods.org/app.
The rest of this post is about how all the pieces come together to make a CocoaPods app.
What's happening under the hood?
Let's take a look at the Xcode Project.
The app is three separate tools that work in combination to provide a seamless experience. You can see the targets; CocoaPods
, pod
and ReflectionService
.
CocoaPods
This is the CocoaPods app, it provides an OS X GUI to common tasks for people who use CocoaPods. It also is the host to an entire environment required to use the CocoaPods' features it exposes. It turns out there are quite a lot of dependencies for CocoaPods once you try to replicate the common user's environment.
In order to make it work seamlessly we bundle: bzr
, curl
, git
, mercurial
, ncurses
, openssl
, pkg-config
, ruby
, scons
, serf
, subversion
, yaml
and zlib
. These are compiled dependencies sitting inside the application bundle. In the Xcode Project above, they are contained in the bundle
reference group.
It's quite the setup in there. It's very similar to how Xcode hosts all of it's SDKs, compilers and apps (Instruments.app, iOS Simulator.app for example.) These folders represent a hosted environment which is well-contained and well tested. We provide the latest stable builds of these dependencies inside the app.
The GUI aspect of the app is built mainly in Swift and Objective-C when necessary. It uses all the fancy modern goodies available in the latest Cocoa APIs: NSViewControllers, Storyboards and XPC.
It's cleanly built using simple composition, and has been the source for quite a few people's first open source contribution. We keep a well stocked issue cabinet with well marked out issues for people wanting to help out. I aim to always put up designs early for features, making it easy for people to contribute with a specification in mind.
pod
We don't plan on replicating every feature of the command-line gem in the CocoaPods app. That's just not good usage of our time. Instead we offer a way to access the command-line interface with the version of CocoaPods that is inside CocoaPods.app. We do this in the same way Xcode does, by offering command line tools:
The pod
command is a C binstub which uses the Core Services API in order to work independent of the CocoaPods.app which installed it. The binstub finds the embedded ruby pod
command generated by RubyGems and passes along the same arguments. This means once you've installed it, you can move your app freely, and we don't need to update the C binstub. Ace.
As it has the same name, you don't need to change any scripts or your development flow in the terminal once installed. I've been using it as my main pod
command for the last few months.
ReflectionService
The CocoaPods app needs to talk to the pod
command provided by ruby. The simplest option is via NSTask, which will execute a command in a shell and output text to STDIN
and STERR
. This makes it easy to run commands, but it can be hard to deal with interactivity. It's effectively a one way communication pattern.
There have been a few tools which bridge Ruby and Cocoa, the most notable being RubyMotion. There is however a bridge that used to come shipped with Mac OS. That is RubyCocoa. We built support for bi-directional communication between Objective-C and Ruby using RubyCocoa.
At one point we had a fork of RubyCocoa that supported objects created in Swift, but that was probably going to turn into a long road for something with not too much gain on our end.
We negated the need for this by moving to communicate with Ruby over XPC, we called this the ReflectionService
. It's explained below.
XPC means that we can have a persistently running Ruby environment from which we can send/recieve metadata about Podfiles. This protects the app from crashes, keeps memory usage low and doesn't require booting up Ruby every time we want to communicate. Triple win. If you've not looked at XPC it gets a thumbs up from us.
What's in now?
The key features for 1.0 are being able to edit a Podfile, and to be able to run pod install
and pod update
on it.
One of the things I'm really happy about is our inline errors for your Podfile. The app gives direct feedback as you're editing the Podfile:
We have a lot of the normal developer key commands working as expected, if there's something you'd want that we don't support, write us an issue or PR.
What's next?
We've got some WIP Pull Requests for some cool features like automatic CocoaPods plugin installation, and an integration summary. These are very likely to be in for the final 1.0 release. However we've not tried to look too far into the future with this app.
I think there's a lot of space for improvements, and we'd love some community input on what you would like to see in a GUI for CocoaPods.
For example, I know when most people try attack this problem they try to solve the pod discovery problem, but I'm not sure if we can do better than the website in the native app. Would love some ideas on ways we could improve.