Cocoapods-sled 让 iOS 组件二进制化变得简单

简介

Cocoapods-sled 是一个简单易用的 Cocoapods 插件,通过缓存和复用Xcode编译结果完成二进制化。它的特性:

  1. 低接入成本:即插即用,没有预编译,也不用双私有源等基建,维护成本低。
  2. 本地缓存:给未匹配到二进制的 pod 插入同步脚本,当 Xcode 执行构建任务时将编译结果缓存到~/Caches/CocoaPods/Frameworks目录下。缓存区分真机和模拟器。
  3. 二进制化处理:自动将可复用的 pod 转换为二进制,源码和二进制丝滑切换。
  4. 所有 Pod 都能复用:Development Pods 编译结果也可以进行复用。

Cocoapods-sled 致力于成为iOS项目构建优化的首选工具之一,帮助开发者以更低的成本实现更高效的开发流程。

开源地址:https://github.com/git179979506/cocoapods-sled

💡目前暂不支持 Library(.a) 复用

实现思路

Xcode 本身有自己的编译缓存 DerivedData,但经常会失效。Cocoapods-sled 插件会把 DerivedData 中的编译结果缓存,当 install 时匹配到缓存就改写 spec 把源码替换为二进制,从而避免不必要的重复编译。当执行pod install [device | simulator]时,大概执行了以下操作:

  1. pod install流程,Downloading dependencies 执行完毕后插入二进制逻辑
  2. 为每个 pod 生成缓存路径
  3. 去对应的缓存路径下查找是否存在缓存
    • 缓存命中:把源码替换为二进制,并进行一些可选的操作,比如生产 Header Search Path 等
    • 未命中缓存:在 Pod Target 的 Build Phases中插入同步脚本,从 DerivedData 提取编译结果缓存到~/Caches/CocoaPods/Frameworks目录下,等待下次复用
  4. 继续执行pod install流程,从 Generating Pods project 开始

安装

Cocoapods-sled 的安装过程非常简洁。你可以通过以下两种方式之一进行安装:

  1. 在应用程序的Gemfile中添加以下行:

    gem 'cocoapods-sled'
    

    然后运行bundle install

  2. 直接在终端中执行gem install cocoapods-sled命令进行安装。

使用方法

获取帮助文档

bundle exec pod install --help
bundle exec pod install device --help
bundle exec pod install simulator --help

开启二进制

cocoapods-sled 给pod install添加了两个子命令devicesimulator,分别对应真机和模拟器。

由于没有进行预编译,二进制缓存是从日常开发产生的缓存 DerivedData 中提取的,无法保证真机和模拟器同时编译并进行包合并,需要手动选择真机或模拟器,这样实现基本满足大多数日常开发场景和打包机打包。

使用device子命令,真机调试和打包开启二进制

bundle exec pod install device

使用simulator子命令,模拟器调试和打包开启二进制

bundle exec pod install simulator

不使用子命令,则不触发二进制逻辑,使用源码(pod install 原逻辑)

bundle exec pod install

使用上面的命令就可以开启二进制了,快去试试吧。
当然插件还提供了丰富的参数和配置用于适配更多开发场景需求。

命令行参数说明

  • --no-binary-pods=pod1,pod2: 禁用指定的 Pod 二进制缓存,多个 Pod 名称用","分隔,优先级高于 --all-binary

    日常开发中,可以和--all-binary配合使用,忽略 Podfile 配置,并指定 pod 使用源码进行开发,避免 Podfile 同时提交协作冲突

  • --binary-pods=pod1,pod2: 只对指定的 Pod 进行二进制缓存,多个 Pod 名称用","分隔,优先级最高

    白名单模式,优先级最高,只为特定 Pod 开启二进制缓存

  • --all-binary: 强制使用二进制缓存,忽略 Podfile 中 :binary => false 设置

    --no-binary-pods=name配合使用,或者在打包机中忽略 Podfile 配置强制开启二进制

  • --configuration=[Debug|Release|自定义]: 编译配置用于生产缓存路径(Debug、Release、自定义),不传则不区分共用,一般用于打包机

    对应 Xcode Build Configuration,支持自定义,当不传此参数时所有configuration产物共用,一般在打包机才需要区分不同 configuration,避免出现Debug、Release环境混乱。

  • --header-search-path: 生成 Header Search Path,一般用于打包机

    适配 OCimport ""方式导入头文件,头文件找不到的情况,使用改标记表示所有pod头生产Header Search Path,也可以在 Podfile 中配置(支持全局生成或单个 pod 生成)

  • --project=name: 工程名称,用于生成framework缓存目录,区分多个工程的缓存

    区分多个工程,一般用于打包机,避免出现一些奇怪的问题

  • --no-dev-pod: 关闭 Development Pods 二进制缓存,默认是开启的
    默认情况 Development Pods 也是开启二进制的,用于适配部分三方库使用 Development Pods 导入的情况,需要注意的是:当 Development Pod 所在目录有变更时不会使用二进制。

  • --force-sync-dev-pod: 强制缓存 Development Pods 编译结果,忽略本地修改检查,默认本地有修改时不缓存,一般用于打包机

    Development Pods 开启二进制时,忽略本地变更检查,一般用于打包机,默认本地有修改时不缓存

  • --inhibit-all-warnings: 强制关闭警告,忽略 Podfile 中的配置,一般用于打包机

    关闭所有 pod 的编译警告,一般用于打包机,减少打包日志输出,方便排查打包失败原因

  • --cache-limit=num: 指定每个 Pod 缓存存储上限数量,小于 3 无效,一般用于打包机

    默认上限是 4 个,可按需调整,缓存数量上限越大则缓存命中率越高,反之越低,⚠️注意磁盘不要被撑爆

  • --dep-check=[single|all]: 检查依赖库版本是否发生变更,single:只检查直接依赖,all:检查全部依赖,一般用于打包机

    用于解决ARC不对齐问题,一般使用--dep-check=single即可,详见常见问题部分

  • --check-xcode-version: 检查xcode版本,不同版本打包不复用,使用 xcodebuild -version 获取版本信息,一般用于打包机

    用于区分不同版本Xcode打出的包,一般用于打包机

Podfile 配置说明

安装 cocoapods-sled 插件后,通过 devicesimulator 子命令就可以触发二进制缓存复用逻辑,不配置 Podfile 也可以正常工作,在 Podfile 中的一些固定配置可以简化命令行参数。

比如可以配置生成 Header Search Paths:sled_enable_generate_header_search_paths!,这样命令行就可以省略参数 --header-search-path

Podfile 中的配置不会影响打包机打包,打包机上可通过参数 --all-binary 配置所有 pod 强制启用二进制。

# 声明需要使用插件 cocoapods-sled
plugin 'cocoapods-sled'

# 标记生成 HEADER SEARCH PATHS
# 用于适配OC使用 #import "" 导入库头文件的情况,默认不生成
# 单个库可通过 :hsp => true | false 设置
sled_enable_generate_header_search_paths!

# 关闭 Development Pod 二进制缓存,默认开启
sled_disable_binary_cache_for_dev_pod!

# 与 :binary => :ignore 等效,用于没有明确依赖的库
sled_disable_binary_pods 'MOBFoundation', 'Bugly'

# 白名单模式,优先级最高。只为 RxSwift 开启二进制缓存,其它配置将失效!!!
sled_enable_binary_pods 'RxSwift'

pod 'RxSwift', :binary => false # 关闭二进制(标记 --all-binary 时忽略该值)
pod 'RxCocoa', :binary => true # 开启二进制(默认为开启,可省略)
pod 'Bugly', :binary => :ignore # 忽略,二进制不做处理(一般用于三方库本身就是二进制的情况,避免出现异常情况,优先级高于 --all-binary)

pod 'QMUIKit', :hsp => true # 生成 HEADER SEARCH PATHS,默认不生成

示例

case1: 开发 SledLogin 和 SledRoute 组件库,使用真机调试

方案一
  1. 修改 Podfile,关闭 SledLogin 和 SledRoute 的二进制

pod 'SledLogin', :path => '../SledLogin', :binary => false # Development Pod

pod 'SledRoute', :commit => 'f02079ae', :git => "#{BASE}/SledRoute", :binary => false # External Pod

pod 'RxSwift', '6.7.0', :binary => false # Release Pod

  1. 执行命令查找真机缓存

$ bundle exec pod install device

方案二(推荐)

每次修改 Podfile 比较麻烦,而且多人协作会互相影响,可以使用命令行参数规避这个问题。

--all-binary--no-binary-pods 组合使用,忽略 Podfile 中的 :binary => false 配置,指定 pod 库关闭二进制。


$ bundle exec pod install device --all-binary --no-binary-pods=SledLogin,SledRoute

case2: 切换到模拟器调试

因为我们之前使用的是真机二进制缓存,所以需要重新执行命令手动切换到模拟器


$ bundle exec pod install simulator --all-binary --no-binary-pods=SledLogin,SledRoute

case3: 打包机打包

# 使用 bundler 保证版本统一
# --all-binary: 强制开启
# --configuration=[Debug|Release|自定义]: 区分不同configuration,避免环境混乱
# --force-sync-dev-pod: 强制开启 Development Pods 二进制,忽略本地变更
# --dep-check=single: 检查直接依赖变更,用于修复偶发的ARC不对齐问题
# --check-xcode-version: 不同版本Xcode编译结果不共用
# --cache-limit=12: 缓存上限数量改为12
# --header-search-path: 全局生成Header Search Path,根据你的项目情况而定,最好不使用
# --project=xxx: 区分不同项目的编译结果

bundle exec pod install device --all-binary --configuration=[Debug|Release|自定义] --force-sync-dev-pod --dep-check=single --check-xcode-version --cache-limit=12 [--header-search-path] [--project=xxx]

常见问题

1. ARC不对齐问题

描述:参考得物 iOS 工程演进之路,全工程编译产物制作:利用编译缓存,从 Xcode 编译缓存 DerivedData 中取出组件。可能会产生ARC不对齐问题,导致 EXC_BAD_ACCESS Crash,具体原因请查看文档。

解决方案:使用--dep-check=[single|all]参数,实际测试--dep-check=single可解决上述偶发问题,但受限于样本量较少,不保证测试结果准确性。

2. #import "" 方式导入的头文件找不到

解决方案

  1. 命令行使用--header-search-path标记,所有 Pod 都会生成 Header Search Path
  2. Podfile配置sled_enable_generate_header_search_paths!,所有 Pod 都会生成 Header Search Path
  3. 单个 Pod 配置 pod 'xxx', :hsp => true,指定 Pod 生成 Header Search Path

3. The 'Pods-xxx' target has transitive dependencies that include statically linked binaries:

描述:可能是在 Podfile 中重写了 build_as_static_framework? build_as_dynamic_framework?等方法,但是没有修改 @build_type属性,verify_no_static_framework_transitive_dependencies 执行时,需要编译的 pod 库都按照修改前的 build_type 检查,导致判断有问题报错:动态库不能依赖静态库。

解决方案:正确修改 @build_type 属性,或者使用 Cocoapods 提供的方法声明 Pod 为静态库或动态库,use_frameworks! :linkage => :static

补充

喜欢就star❤️一下吧

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容