background

In the development process of a company level project, it is inevitable that the project will be too large, resulting in the reduction of compilation and development efficiency. In how to improve the compilation speed, speed up production efficiency, each big factory has a variety of attempts, but unfortunately in the industry does not have a low cost, good effect of open source solution. In the company where the author works, due to the convergence of business lines, the original two completely different business lines are merged into the main App in the form of components, exacerbating the compilation problem. The full compile time of the project went from 5 minutes to about 25 minutes, and the packing of CI continued to move toward 30 minutes.

Train of thought

Cocoapods-binar is an overall practice for binarization, rather than a single private library like CocoapoDS-Packager. Binarization — simply using podSpec to point the source to a pre-packaged binary to improve compilation efficiency — is the prevailing practice. You can also change the compilation cache such as CCache or change the compiler to Buck (FB)/Bazel (Google) to implement distributed compilation. This article of wechat compilation speed optimization by the wechat team has carried out a relatively complete elaboration. In this article, cocoapods-binary will be precompiled with dependencies and cached locally. Then link the original Source Code to the Binary at almost no cost. The only downside is the lack of server-side caching (something we need to tweak, but this can be customized), so called distributed binary compilation.

CocoaPod-Binary

I first discovered this plugin when I was browsing the official blog, and the author was a domestic developer. The plug-in was also released over two years ago and is currently supported to Pods version 1.6.x. Let’s first look at the class diagram composition:

CocoaPods itself provides a good template for plugins, so check out this article if you need it. The core cocoapods-binary code is in the lib/cocoapods-binary folder. Let’s take a look at the main parts of the plug-in and what they do.

Main

The pre_install hook is provided by CocoaPods to intercept the pod install context during the Prepare phase of the pod install. Fork out a separate Installer to complete the clone of the precompiled source code to the Pod/_Prebuild directory.

Helper

Attribute states are added to Sandbox, Installer, Pod, and Podfile Options classes to meet logical requirements. For example, subclass Sandbox > PrebuildSandbox to specify the address of generate frameworks, the address of prebuild Pods, and whether a compiled framework exists. Add binary and all_bianry keywords to the Podfile DSL to control binary and source switching.

Room Build Framework

Compile all :binary => true dependencies into binary and dSYM with xcodeBuild and output to the specified directory. Here, an extra step is made for the framework output on iOS platform. When detecting platform or iOS, the simulator and real machine devices will be compiled separately. Finally, libo is used to combine their binary and dSYM into one output.

Prebuild Installer

Taking advantage of the dynamic nature of ruby, Overload Installer’s run_plugins_post_install_hooks to trigger build Framework to package Dependencies into a binary package after pre_install ends. Check whether file xxx_name exists in the generated framework to check whether the lib has been compiled. (XXX indicates the name of the corresponding lib.)

Integration

After the plug-in source code is synchronized and precompiled, the install context is returned to enter the final install phase. At this point, we will complete the symbol link to the binary frameworks to replace the original Pods source code and the Embed operation will modify the individual pod. xcProject configurations to generate the project.

The results of

With the basic modules out of the way, let’s take a look at what Pods files look like when cocoapods-Binary is introduced:

The _Prebuild directory contains a complete copy of the Pods source code, while the GeneratedFrameworks of the extra binary files and dSYM symbol tables are cached. In the final integration phase, after the symbol link is replaced, the source code is removed and points to binary.

So far, the whole Pod install is complete, what are the limitations of CocoaPods?

  • Because CocoaPods is in 1.7.x or above, we have changed the framework generation logic to not copy the bundle to the framework, so we need to fix the Pod environment to 1.6.2;
  • In order for pod to support binary, header ref needs to be changed to either #import <> or @import to comply with the Moduler standard.
  • Unified CI and development compiler environment. If the project supports Swift, different compiler products may have compatibility problems with Swift versions;
  • The final binary size will be larger than when using the source code. It is not recommended to upload the final Store.
  • You are advised to ignore the Pods folder. Otherwise, there will be a lot of file changes during the switch between source code and binary.

The flow chart

This simple flow chart will hopefully help you understand the basic idea of cocoapods-Binary.

About Me