24 June 2015
Follow @ortaPeople have been asking for years about feedback on how many downloads their libraries have. We've been thinking about the problem for a about as long too, and finally ended up asking Segment if they would provide a backend for the project.
But wait, there's more...
It wasn't just enough to offer just download counts. We spend a lot of time working around Xcode's project file intricacies, however in this context, it provides us with foundations for a really nice feature. CocoaPods Stats will be able to keep track of the unique number of installs within Apps / Watch Apps / Extensions / Unit Tests.
This means is that developers using continuous integration only register as 1 install, even if the server runs pod install
each time, separating total installations vs actual downloads.
Alright, hold up
Let's go over how we check which pods get sent up for analytics, and how we do the unique installs. CocoaPods-Stats is a plugin that is now bundled with CocoaPods from version 0.38 onwards. It registers as a post-install plugin and is ran on every pod install
or pod update
.
Detecting Public Pods
We're very pessimistic about sending a Pod up to our stats server. We ensure that you have a CocoaPods/Specs repo set up as your master repo, then ensure that each pod to be sent is inside that repo before accepting it as a public domain pod.
Data being sent
First up, we don't want to know anything about your app. So in order to know unique targets we use your project's target UUID as an identifier. These are a hash of your MAC address, Xcode's process id and the time of target creation (but we only know the UUID/hash, so your MAC address is unknown to us). These UUIDs never change in a project's lifetime (contrary to, for example, the bundle identifier). We double hash it just to be super safe.
# Grab the project and the type of target
uuid = target.user_target_uuids.first
project_target = project.objects_by_uuid[uuid]
# Send in a digested'd UUID anyway, a second layer
# of misdirection can't hurt
{
:uuid => Digest::SHA256.hexdigest(uuid),
:type => project_target.product_type,
:pods => pods
}
We then also send along the CocoaPods version that was used to generate this installation. Ideally before release we'll also be able to give statistics on how many people are using pod try [pod]
for your library too.
How does it work?
My first attempt at a stats architecture was based on how npm does stats, roughly speaking they send all logs to S3 where they are map-reduced on a daily basis into individual package metrics. This is an elegant solution for a company with people working full time on up-time and stability. As someone who wants to be building iOS apps, and not maintaining more infrastructure in my spare time, I wanted to avoid this.
We use Segment in Artsy, and our analytics team had really good things to say about their Redshift infrastructure. So I reached out about having them hosting the stats infrastructure for CocoaPods. They offered a lot of great advice around the data-modelling, we were up and running really quickly. So you already know about the CocoaPods plugin, but from there it sends your anonymous Pod stats up to stats.cocoapods.org. This acts as a conduit sending analytics events to Segment. A daily task is triggered on the web site, this makes SQL requests against the Redshift instance which is then imported into metrics.cocoapods.org.
FAQ
Can I opt out as a CocoaPods user?
Sure. You can set an environment variable COCOAPODS_DISABLE_STATS
to true in your shell, and stats will not be sent from your machine.
Does this affect every pod?
Yeah, every pod will get download stats.
Will it be live stats?
No, they get generated once per day.
What is the rollout strategy?
We plan on making this initially a separate CocoaPods plugin that you can optionally install via [sudo] gem install cocoapods-stats
which will send the data. In a release or two we will bundle this into CocoaPods, and it will be installed by default for everyone moving forwards.
Can I use it right now?
Sure, update to the latest CocoaPods [sudo] gem install cocoapods
or download the latest CocoaPods.app.
How does this affect the quality indexes / sorting?
Ideally we can reduce the amount of impact GitHub stars affects a quality index, and replace some of the values with new metrics based on downloads/installations.
What commands does this run on?
It runs at the end of a pod install
or a pod update
.
I check in my Pods directory, how does this affect stats for the pods I use?
Checking in your Pods directory will mean that the download count for the pods used will rarely be affected, but the installations will be the exact same. They only register once per project, so multiple developers on the same project running pod install
will not raise this number.