Pod 预编译,减少不必要的生命浪费

3,355 阅读4分钟

前言

随着越来越多的业务量,以及添加的各种第三方库,礼物说这个项目的编译时间也飙升到了五分钟以上。虽说和微博、美团、滴滴他们的三十分钟不是一个数量级,但每天好几个五分钟也会浪费不少人参。于是,加速编译就会被拉上日程。

基本思想

项目组件化后用 Pod 管理,然后 Pod 里面维护的不是源代码,而是静态链接库。这样最终编译的时候,只需要进行部分编译加链接签名,完成打包。

据说,美团使用这项技术之后,编译时间从原来优化到二百秒。然而,具体实现过程没有任何教程和文档。完全要投石问路。

流程

这件事肯定要有 CI,也就是持续集成。但抛开这件事不谈,我们可以先把问题简化成,一个能正常使用的Pod,执行一个 WorkFlow,即可生成一个预编译好的 Pod。

于是就对这件事进行子任务拆分,可以得到这么个流程:

  1. 创建一个 Xcode 工程
  2. 生成 Podfile,进行 Pod Install
  3. 生成静态链接库
  4. 解析原有 PodSpec,修改里面的 sourcecode 为 *.h 并添加静态链接库
  5. 发布

听起来很简单,事实上各种坑。

创建一个 Xcode 工程

问题来了,如何才能创建呢。Google 了一下,没有什么解决方案。看起来只有 AppleScript 可以,真的要学一下 AppleScript 么?

我们来换个思路想这个问题,创建工程的目的是什么,是为了给 Pod 一个编译环境。那么只要是个空的静态项目就行了啊,没必要每次都创建。

于是我们可以创建一个模板工程,丢到 Git 或者 七牛上去。

这里需要注意一个问题,工程里面一定要有个类,否则他不会编译的。


生成 Podfile

这个直接 echo 一下就好了,对于想要修改的 Pod 应该算是直接按照这个模板 echo 一下就好了

target 'Template' end

而可替换内容,应该是脚本的传入参数。例如 AFNetworking ~> 2.4

生成静态链接库

这里我们选择用 xcodebuild 来打包,为了省掉配置 fastlane 的过程,但这里需要注意个问题。我们目标是生成静态链接库,所以我们要保证 i386x86_64armv7arm64 四个平台都要有。然而这是没法一次性编译出来的。

xcodebuild -workspace Template.xcworkspace \
              -scheme Template \
              -configuration Release \ 
              build \
              CONFIGURATION_BUILD_DIR=~/Desktop/workspace/Template/build

注意 CONFIGURATION_BUILD_DIR 需要绝对路径,相对路径会报找不到文件的错误。

xcodebuild -workspace Template.xcworkspace \
              -scheme Template \ 
              -configuration Release \ 
              clean build \ 
              CONFIGURATION_BUILD_DIR=~/Desktop/workspace/Template/build \
              ARCHS='i386 x86_64' \ 
              VALID_ARCHS='i386 x86_64'\
              -sdk iphonesimulator

相对于 arm 平台,这个版本多了 clean, ARCHS, VALID_ARCHS, -sdk 这几个参数来保证编译顺利通过。

lipo -create libSignatureLibary_armv7.a libSignatureLibary_i368.a -output libSignatureLibary.a

解析原 podspec

想解析原 PodSpec,我们就要找到它在哪。 Pod 提供了一个方法

pod spec which AFNetworking --show-all

可以打印本地所有版本的 AFN 的 Spec。毕竟 ~> 以及 platform 多种因素导致,我们不知道确切安装的版本。


然后配合 Podfile.lock 文件,就能找到我们想要的那个 spec 了。

然而 SPEC 有两种写法: ruby / json,解析起来蛮蛋疼的,我们可以通过 Pod 的工具转换成 json。

pod ipc spec xxx.podspec > xxx.podespec.json

终于可以解析了。

解析主要是把原来的 source_files 字段,改成 *.h。
以及添加 vendored_library 字段。这一块坑还是蛮多的,我们也还在持续踩着。比如 dependenciessubspecs 有各种复杂的情况,只能发现的时候再处理了。

发布

生成了一坨东西之后,怎么管理就成了问题。我难道用一个第三方库就要给他创建一个 git 么?通过阅读文档,发现 Podfile 有这么一种写法:

pod 'JSONKit', :podspec => 'https://example.com/JSONKit.podspec'

于是我把我上一步修改的 spec 填入后面就可以了。如果想要源代码就在 :podspec 前面加一个 # 注释掉。

然后再说内容托管在哪。 Spec 支持多种方式:


其中的 http 可以做到往里面关联一个 zip,例如友盟的 Pod 就是这么做的。

查看图片

我们把之前生成的 .a 和代码中的 .h 打成包,丢到万能的免费云七牛上就可以了。

后记

这篇文章来源于昨晚骑车回家时的一点灵感,晚上实现了一下。今天又和同事讨论细化了一下做出来的。可能很多地方做的不够细致,欢迎大家指正。若有更好的方案,也欢迎大家告诉给我。