Xcodebuild 编译加速,Cocoapods 二进制化实践
Posted TesterHome
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Xcodebuild 编译加速,Cocoapods 二进制化实践相关的知识,希望对你有一定的参考价值。
背景
为了加快当前ios项目的编译速度,加速编译被放上日程。从网上看了很多这方面的方案,最后选择了Pod二进制化,来加速一些编译速度,原理是工程引用库后在编译阶段就不需要对Pod库进行编译。
目标
我们当前的目标是将私有库编译成二进制文件后,但是有一些限制:
尽量做到不侵入我们的工程源码,比如不更改
import
方式等推进所有三方库二进制化,包括我们的私有库和
github
上的三方库不破坏当前cocoapods管理依赖库的原则
基本思路
由于我们不能破坏当前的Pod管理方式,需要做的就是将当前项目工程中的源码替换成静态链库,最后编译的时候只需要对工程源码进行编译,不用编译Pod库,只需要最后的链接签名,完成打包。
搜索到的方案
CocoaPods组件平滑二进制解决方案
采用了cocaoapods-packager和shell脚本生成Framework,但是需要手动添加新的target
Carthage管理
采用carthage管理当前的依赖库,但是为了不大动我们的项目,所以不能切换工具
最后的方案
需要钱解决的核心问题有:
将所有库打成Framework
引入方式,当前的引入方式是执行
pod install
然后下载各种pod的依赖,好处是cocoapods可以管理所有互相依赖的问题不能将打好的Framework手动拖拽进项目,要以最小的代价完成替换
解决打Framework的问题
我们可以使用xcodebuld,Fastlane的gym,或者cocoapods packager实现打包,但是这几种方式我都尝试了一下,并未成功,最后发现Carthage可以非常方便的实现库变成Framework。
使用命令carthage build --no-skip-current --platform iOS
我们只需要关注iOS平台,故只选择iOS平台即可
但是在这里我们需要做一个区分,三方库是否支持Carthage化,换句话说就是这个库是否已经进行过Carthage化了。
根本的区别是在share scheme,当这个库已经支持Carthage了,比如AFNetworking,AFN已经支持Carthage了,直接下载库后,然后再根目录执行
carthage build --no-skip-current --platform iOS
结果为:
*** xcodebuild output can be found in
/var/folders/my/cl8q6md51nz8vq85cvr5ncc40000gn/T/
carthage-xcodebuild.jfnLwA.log
*** Building scheme "AFNetworking iOS" in AFNetworking.xcodeproj
如果是未进行Carthaeg化的呢,如果同样执行的话,结果是:
*** xcodebuild output can be found in
/var/folders/my/cl8q6md51nz8vq85cvr5ncc40000gn/T/carthage-xcodebuild.eBdI
4c.log
*** Skipped building category due to the error:
Dependency "xxx" has no shared framework schemes for any of the platforms: iOS
那么如何做到依然打出Framework呢?
我们需要做的流程是:
首先,强调我们的私有库是官方标准格式的私有库
pod lib create xxx
现在我们需要修改的是用
打开Example下的对应示例工程的xxx.xcworkspace,用xcode打开
然后选中Manage Scheme
这个时候重新回到根目录下,执行
carthage build --no-skip-current --platform iOS
便能方便的生成一个已经二进制化的Framework,同时里面还有我们需要的
headers
。
解决引入方式的问题
谈到这里,我们需要关注一下cocoapods是如何管理依赖库的?
我们都知道pod install之后会下载从Pod Spec里面拉取源码,然后放到工程目录Pod下面进行管理,然后也有些库是直接拉取之后,以Framework的方式引入,比如友盟,OpenCV,Fabric等。
我们先看看友盟的podspec.json
是如何实现的?
可以看到友盟提供的依赖下载就是.zip包,存储的便是Framework。
我们再可以拿OpenCV这个库来看一下:
它的实现显然是不一样了:
先 pod install来 lone 代码
prepare_command执行build.py,类似于编译开源项目时常见的./configure
prepare_command结束后,由Cocoapods把framework插入Xcode工程中
我们注意到Prepare_command的命令,它是用来干嘛的呢?
CocoaPods prepare_command支持各种脚本的使用,Python Shell Ruby
意味着,如果我们不想改动之前的pod install管理依赖包的模式,只需要在podspec.json里面增加prepare_command脚本,然后执行打包下载,便可以将源码打包成Framework无缝引入我们的项目中,然后我们拿三方库mantle示例一下,
先fork mantle到自己的github仓库下,然后更改新建mantle.podspec.json:
{
"name": "Mantle",
"version": "2.1.3",
"summary": "Model framework for Cocoa and Cocoa Touch.",
"homepage": "https://github.com/diaojunxian/Mantle.git",
"license": "MIT",
"authors": "txx",
"source": {
"git": "git@github.com:diaojunxian/Mantle.git",
"branch": "mantle"
},
"platforms": {
"ios": "8.0"
},
"requires_arc": true,
"frameworks": "Foundation",
"vendored_frameworks": "Carthage/Build/iOS/Mantle.framework"
"prepare_command": "python mantle_build.py"
}
再在项目中新建mantle_build.py文件
#coding=utf-8
import os
import subprocess
import sys
path = os.path.join(os.path.abspath('.'))
file = open('Cartfile', 'w')
file.write('github "Mantle/Mantle"')
file.close()
command = 'carthage update --platform iOS'
subprocess.check_output(command, shell=True)
sys.stdout.write('Pass!\n')
这个脚本做到的就是将mantle的源码打成framework然后倒入到项目工程中。
其实,这里强调了很多关于prepare_command的内容,是因为它给了我灵感,我们上一大步已经实现了打成Framework,这里如果只考虑引入的话,只需要两步
:
第一步:将打包成framework推入我们之前的项目pod源码中,并将我们的pod库中的podspec.json改成:
"name": "Mantle", "version": "2.1.3", "summary": "Model framework for Cocoa and Cocoa Touch.", "homepage": "https://github.com/diaojunxian/Mantle.git", "license": "MIT", "authors": "txx", "source": { "git": "git@github.com:diaojunxian/Mantle.git", "branch": "mantle" }, "platforms": { "ios": "8.0" }, "requires_arc": true, "frameworks": "Foundation", "vendored_frameworks": "Carthage/Build/iOS/Mantle.framework"
然后执行验证
pod lib lint Mantle.podspec.json --allow-warnings --verbose pod spec lint Mantle.podspec.json --allow-warnings --verbose
pod spec lint 和 pod lib lint 最主要的区别是,前者会根据 spec 文件 tag 信息去验证远程仓库代码是否存在,后者不会。简单理解就是,pod spec lint 联网检查,pod lib lint 不联网检查。
第二步:向私有Spec.ios推送私有库
pod repo push xxx Mantle.podspec.json --allow-warnings
同样的不需要更改工程中的podfile内容,然后执行pod install,这个时候工程中下载的依赖便是framework。
引用方式
源码库中以framework形式存储了库,那么引用方式是否需要更改呢?
其实最标准的引用方式是:
#import <Mantle/mantle.h>
由于我们的工程中存在这大量不合理的引用方式,比如:
#import "mantle.h"
当我们以framwork方式引入后,可能会有报错,有一个简单的方法去解决:
平滑更改Build Settings中对应项Header Search Paths,不影响当前所有项目的引用依赖方式。
这里的recursive是从根目录开始递归查询引用文件
然后就可以规避引用方式报错的问题,但是这样的引用还是有问题,需要我们开发进行更改。
打包时间是否优化?
当前我更改了3个库,打包的时间由1分钟左右的缩短,打包的体积未发生变化。
不知道算不算优化。
后续还需要将所有的引用库二进制化后观察。
参考
https://imfong.com/post/Talk-iOS-Library-Binary-Practice#clean
https://blog.dianqk.org/2017/05/01/dev-on-pod/
以上是关于Xcodebuild 编译加速,Cocoapods 二进制化实践的主要内容,如果未能解决你的问题,请参考以下文章