February 12, 2016

Cocoapods, GoogleMaps and Github 100 Mb restrictions

On some mobile app projects we’re developing, we’re using CocoaPods. More than that, in some projects, where we’re using CocoaPods, we’re adding the Pods directory to the source control. There are reasons for that. There are a few drawbacks to that approach, but our goal is to be sure that anyone can build a mobile app project right after cloning it.

We’re using Github for the repository and after the latest Google Maps version upgrade, Github started to decline our pushing attempts. This was because some of our files appeared to be more than 100Megabytes in size.

The problem file was Google Maps framework which was about ~114MB.

What to do?

There were a few ways we were thinking about handling this “feature”:

  • Stop pushing CocoaPods to the repo.
  • Stop using Google Maps in the project.
  • Divide Google Maps into smaller files, and recombine them on the build machine.

Decisions

When this problem occurred there wasn’t enough time to start experimenting with alternative options. Installing CocoaPods could take a while. On our integration server we were using a clean setup each time, so if we’d decided to set up CocoaPods each time on the server, we would’ve increased build time dramatically.

Also, we weren’t able to just remove Google Maps from the project at that point in time because the deadline was near.

Therefore we decided to leave CocoaPods in the repository, but deal with the big files somehow.

Below you can see our solution to use in iOS app development:

Solution

The idea was as simple as it could be – divide the big file into the smaller ones, and combine small parts in the original file on the build server.

Splitting up the file

In order to split the file, we’ve added few lines to our Podfile:

post_install do |installer_representation|
    puts "Splitting up Gooogle Framework - It's just too big to be presented in the Github :("
    Dir.chdir("Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/Current") do
       # Remove previous split files if any
       `rm GoogleMaps_Split_*`
       # Split current framework into smaller parts
       `split -b 30m GoogleMaps GoogleMaps_Split_`
    end
end

The solution, as you can see, is pretty straightforward – each time the pods are being installed, we’re splitting up the framework to smaller 30MB chunks.

Adding the framework file to .gitignore

Since we cannot push this file to the repo, we need to remove it from the index and add it to .gitignore.

# Google Maps is too big to be handled by one file, so this one is generated on build phase from smaller pieces
OurProject/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/GoogleMaps

Combining chunks in the original file

Since we’re not using pod install on the build server (that is what this is all about, actually), we need a place where we can combine the file again – we only have small chunks in the repository. So in our case we’ve added an additional build phase in the xcode project, which looked like this:

# Github doesn't support files bigger than 100M.
# Latest checked GoogleMaps Framework ~ 114M
# We're expecting to have GoogleMaps Framework as a one file or as a number of chunks

BINARY_FILENAME=GoogleMaps
SPLIT_FILENAME_PREFIX=${BINARY_FILENAME}_Split
GMAPS_FRAMEWORK_DIR=Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/Current
GMAPS_FRAMEWORK_FILE=$GMAPS_FRAMEWORK_DIR/$BINARY_FILENAME

# Check if we  have Google Maps Framework
if [ ! -f ${GMAPS_FRAMEWORK_FILE} ]; then
    echo "There's no Google Maps framework at ${GMAPS_FRAMEWORK_FILE}"
    cd ${GMAPS_FRAMEWORK_DIR}
    #  But we have chunks! ...Probably
    if [ -f ${SPLIT_FILENAME_PREFIX}_aa ]; then
       echo "Creating file from smaller files with ${SPLIT_FILENAME_PREFIX} prefix"
       cat ${SPLIT_FILENAME_PREFIX}_* > ${BINARY_FILENAME}
    fi
fi

Profit

This is how we solved this mobile app development issue. By doing this we bought some time to make a long-term decision about how to handle this issue. Of course it’s just a temporary solution.