布景:

跟着业务的开展免不了带来工程代码的飞速添加,程的业务代码数量逾越10w行的非常遍及,运用的的二方/三方 Pod 库的数量也会持续添加,工程的急速膨胀给我们的日常开发中带来了许多痛点,在项目体量越来越大的情况下,编译速度也随之增长,工程编译速度下降,clean-build 一次需求 10-15min 左右,现在在大部分项目中xcode全部编译一次少则5分钟,多则10多分钟,乃至更久,严峻影响开发效率。有时分一个小的改动也需求等候长达好几分钟的编译时间,打包速度下降,在打包提测窗口添加了等候的时长,在硬件资源有限的情况下,而且在不影响业务方开发习气的条件下,怎样处理这些摆在团队面前的难题,便成了我们迫在眉睫的火急需求。

处理方案

针对这个问题,做了多方面的根究,从业界方案参看来看大约有以下几种策省掉处理。

  1. xcode 编译选项优化

  2. 编译生成中心产品CCache优化

  3. 直接生成二进制编译

一. Xcode 编译选项优化

1.Xcode配备

1.1. Enable build duration setting in Xcode

你可以直接在 Xcode 的 UI 中启用计时器。默许情况下此计时器不可见,但假设在指令行中工作以下指令,则每次构建应用程序时都会显示一个时间。

启用计时器后,您将在 Xcode 的构建情况栏中看到编译应用程序所需的时间。

终端输入:

$ defaults write com.apple.dt.Xcode ShowBuildOperationDuration YES

启用计时器后,重启xcode ,您将在 Xcode 的构建情况栏中看到编译应用程序所需的时间。

iOS编译速度优化实践

1.2运用新的构建体系

Apple 在 Xcode 9 中推出了一个新的构建体系,但默许情况下并未激活。Apple 的“New Build System”完全用 Swift 编写,旨在进步全体功用和依托处理。但是,关于 Xcode 10,新的构建设置已默许激活并从Xcode Files-> Project/Workspace Settings启用

iOS编译速度优化实践
您可以在作业区设置中或通过调用以下方法启用它:

xcodebuild -UseNewBuildSystem=YES.

1.3.添加正告以检查函数或表达式是否导致编译时间变长

Xcode 具有内置功用,可让您辨认导致编译时间变长的函数和表达式。您可以指定编译时间束缚并承认代码库中超出此束缚的区域。

在项目构建设置“其他 Swift 标志”中添加以下行


-Xfrontend -warn-long-function-bodies=300
-Xfrontend -warn-long-expression-type-checking=300

iOS编译速度优化实践

300 整数表明您对函数和表达式设置的编译时束缚。它以毫秒为单位。

假设函数或表达式花费的时间逾越您指定的时间,这些标志将正告您。这意味着您必须优化您的函数或表达式。

iOS编译速度优化实践

1.4.添加 Xcode 线程数

默许情况下,Xcode 将运用与 CPU 内核数相同的线程数。添加 Xcode 运用的线程数可以显着进步编译功用。这运用了一些处理器的多线程或仿照额外内核的才干。请记住,您或许需求进行实验以承认运用代码库进行并行构建的收益是否递减,然后相应地调整线程数。让我们检验将 Xcode 配备为运用 3、4 或 8 个线程,看看哪一个为您的用例供应最佳功用。

您可以设置 Xcode 从终端运用的进程数,如下所示:

$defaults write com.apple.Xcode PBXNumberOfParallelBuildSubtasks 4

1.5.添加为 Swift 项目工作的并发构建任务的数量

在 Xcode 9.2 中,Apple 引入了一项实验性功用,答应 Xcode 并行工作 Swift 构建任务。默许情况下,此功用未启用,您需求从指令行自行翻开它。

默许写入

com.apple.dt.Xcode BuildSystemScheduleInherentlyParallelCommandsExclusively -bool YES

1.6.调整 iOS 仿照器(当然可以选择运用真机)

Apple iOS 检验仿照器让您可以跨不同的软件和硬件组合进行检验。通过运用 Physical Size 或 Pixel Accurate 窗口大小,您可以减少检验的大小和结束检验所需的时间。终究,这些配备更改运用的资源更少,有助于避免检验速度变慢,可以选择并拖动仿照器的任何角落以调整其大小并根据您的要求进行设置。其他,您可以按 CMD+1、CMD+2 或 CMD+3

1.7.并行构建

此选项答应 Xcode 通过一起构建不相互依托的政策来加快总构建时间。关于具有许多可以轻松并行工作的较小依托项的项目,这可以节约时间。

在 Xcode 10 中翻开项目时,构建并行化应该现已启用。要检查或更改此选项,请翻开方案编辑器,在边栏中选择“Build”并确保在顶部选中“Parallelize Build”。

iOS编译速度优化实践

1.8.仅构建活动架构

当您的调试配备被选中时,您的项目应该只构建活动架构。默许情况下,此设置应处于活动情况,但值得检查以防万一。

导航到Build Active Architecture Only项目的构建设置中。确保 Debug 设置为Yes而且 release 设置为No。

iOS编译速度优化实践

确保为您的调试配备将 Build Active Architecture Only 设置为 Yes

2.恰当的构建设置

2.1.优化 dSYM 生成

DWARF: 是一种广泛运用的规范化调试数据格式。DWARF 开端是与可实行和可链接格式 (ELF) 一起设计的,尽管它独立于政策文件格式。

调试符号 (dSYM): 默许情况下,应用程序的调试版别将调试符号存储在已编译的二进制文件中,而应用程序的发布版别将调试符号存储在配套的 dSYM 文件中以减小二进制文件的大小。

DWARF 和带有 dSYM 文件的 DWARF 有什么差异?

不同之处在于,关于带有 dSYM 文件的 DWARF,您的存档 app.xcarchive(用于 AdHoc 分发)还包括在溃散陈说中对代码进行反向符号化所需的 dSYM 文件。因而,假设您需求它在归档您的应用程序以进行分发时对溃散陈说进行外部剖析,您应该将 DWARF 与 dSYM 文件一起运用。在 OSX 的前期阶段,Apple 不想阅历在其链接器中引入DWARF支撑的费事。他们为此目的创建了一个单独的链接器 (dsymutil),它从政策文件中获取调试信息并将其放在一个一般的地方:一个 dSYM 包。

尽管 dSYM 绑缚包对发布构建很有用,但在开发进程中不需求它们。调试器可以从构建后依然存在的中心政策文件中获取调试信息。

在 XCode 中,我们可以将构建的“调试信息格式”设置为“DWARF”而不是“DWARF with dSYM File”。

确保您设置Debug Information Format为一直为您的发布版别和未在仿照器上工作的调试版别创建 dSYM 文件。在 iOS 仿照器上工作时不需求创建它们。

iOS编译速度优化实践

在 iOS 仿照器上工作时不该生成 dSYM 文件,但应为全部其他实例生成

2.2.全模块优化 (WMO)

在 Xcode 中,我们可以选择三个优化等级:NoneFastFastWhole Module Optimization

运用 Whole Module Optimization 使编译速度非常快。但是选择快速或快速,整个模块优化将不答应开发人员调试应用程序。

iOS编译速度优化实践

2.3 优化等级

优化等级有两个不同的部分

1.Apple LLVM 9.0 Code Generation -> Optimization Level -> Debug GCC_OPTIMIZATION_LEVEL
有6个优化等级。

GCC_OPTIMIZATION_LEVEL =
fast(最快和活跃的优化)
s(最快和最小)
3(最快)
2(更快)
1(快)
0(无)

iOS编译速度优化实践

  1. Swift Compiler Code Generation -> Optimization Level -> Debug SWIFT_OPTIMIZATION_LEVEL

有3个优化等级SWIFT_OPTIMIZATION_LEVEL =-Onone-O (Fast Single File Optimization)-Owholemodule (Fast, Whole Module Optimization)

iOS编译速度优化实践

运用Whole Module Optimization使编译速度非常快。但是选择快速或快速,整个模块优化将不答应开发人员调试应用程序。

3.代码优化

3.1 优化代码

我们可以优化代码,这将有助于我们缩短编译时间。我们添加了其他链接器标志-warn-long-function-bodies & -warn-long-expression-type-checking来辨认编译时间过长的函数和表达式,现在我们需求手动优化这些表达式或函数.

  • 对类自身中扩展 v 的方法中的方法进行基准检验。
  • 添加类型注释,以便编译器不需求揣度类型。
  • 避免三元运算符, ?:
  • 通过手动解包来避免运用 nil 合并运算符if let
  • 运用字符串插值而不是连接。

3.2第三方依托

有一些非常盛行的依托处理技术/东西:Cocoa Pod、Carthage、Swift Package Manager、git Submodule。

在 iOS 项目中处理 3rd 方依托项的最常见方法是运用 CocoaPods。它运用简略,但假设您关怀构建时间,则它不是最佳选择。

您可以运用的一种替代方法是Carthage。它比 CocoaPods 更难运用,但它会缩短您的构建时间。

3.3优化 CocoaPods

假设您运用 CocoaPods,您可以通过将以下内容添加到 Podfile 的结尾来优化全部依托项。


post_install 实行 |installer|
 installer.pods_project.targets.each 做|政策|
  target.build_configurations.each 做 |config|
   假设 config.name == 'Debug'
    config.build_settings['OTHER_SWIFT_FLAGS'] = ['$(inherited)', '-Onone']
    config.build_settings['SWIFT_OPTIMIZATION_LEVEL'] = '-Owholemodule'
   end
  end
 end
end

3.4 对代码的小改动

  • 当您知道不需求掩盖声明时,请运用“final”。要害字final是对类、方法或特色的声明的束缚,使得声明不能被掩盖。这意味着编译器可以宣布直接函数调用而不是直接调用。

  • 当不需求在文件外部访问声明时,运用“private”和“fileprivate”。将private或fileprivate要害字应用于声明会将声明的可见性束缚在声明它的文件中。这答应编译器可以承认全部其他或许掩盖的声明。

  • 在数组中运用值类型:在 Swift 中,类型可以分为两个不同的类别:值类型(结构、枚举、元组)和引用类型(类)。一个要害的差异是值类型不能包括在 NSArray 中。因而,当运用值类型时,优化器可以消除 Array 中的大部分开支,这些开支是处理数组支撑 NSArray 的或许性所必需的。

  • 其他…

二. 编译生成中心产品CCache优化

https://github.com/ccache/ccache

https://ccache.dev/performance.html

Ccache 是一个编译器缓存。它通过缓存从前的编译并检测何时再次进行相同的编译来加快从头编译。

cache 的功用取决于许多因素,这使得很难猜测给定用例的改善。假设预期射中率较低,则因为缓存未射中的开支(一般为 5%-20%,但启用依托方法时仅为 1%-3%),运用 ccache 时或许会呈现净功用丢失).此外,假设与构建东西(编译器、链接器等)运用的内存量比较构建机器的内存不足,则运用 ccache 或许会下降功用,因为 ccache 的缓存文件或许会改写操作体系磁盘中的其他文件缓存。

iOS编译速度优化实践

利益:

  1. 无侵入、无影响现有的业务的要求,无侵犯、开发人员无感知。
  2. 在某些情况下能大幅度地提升编译速度。
  3. 不需求对项目作出大调整,只需布置相关环境和一些脚本支撑。
  4. 不需求改动开发东西链。
  5. 同一个目录下,CCache 的缓存射中率相对安稳。

存在些某问题:

  1. 在未有缓存的情况下,初次打包编译的时间比原本的翻近一倍,原本20+min,初次将近40+min,在资源严峻的情况下,乃至是更多。
  2. 批改一些引用较多的文件(如公共库、底层库改动),简单形成大范围的缓存失效,速度会变得比原本未运用ccache时更慢。
  3. 多个项目相同的组件不支撑缓存同享,有多个分支打包的需求,批改目录称号后,缓存即失效。
  4. 机器的Ccache有最大的缓存上限,且Debug/Release差异缓存,多个项目、多个分支很简单超出上限,一台Ci机器一起支撑多个项目会触发CCache清缓存。
  5. 对机器硬盘读写要求高,如不是全部固态硬盘,速度影响大。
  6. CCache 不支撑 Clang Modules,体系框架例如 AVFoundation、CoreLocation等, Xcode 不会再帮你自动引入,会导致编译失利。
  7. CCache 不支撑 PCH 文件
  8. CCache 现在不支撑 Swift

三. 直接生成二进制编译

先看下编译流程,我们每次编译工程大约如下,那么假设能直接省掉前边从预处理到生成二进制文件的进程,不就处理了编译时间的问题么。

iOS编译速度优化实践

1.cocoapods-binary

cocoapods-binary 通过开关,在 pod insatll 的进程中进行 library 的预编译,生成 framework,并自动集成到项目中

整个预编译作业分成了三个阶段来结束:

  • binary pod 的设备
  • binary pod 的预编译
  • binary pod 的集成

Binary Pod 的设备

Binary Pod 的设备作是以pre_installhook 作为进口,开端插件的运作。

iOS编译速度优化实践

Binary Pod 的预编译

cocoapods-binary 在下载 binary pod 源码前会先检查是否现已有预编译好的二进制包,假设没有缓存才会开端binary pod 的下载和预编译。

iOS编译速度优化实践

binary pod 的集成

具体可以看 github.com/leavez/coco…

存在许多束缚

1.CocoaPods 在 1.7 以上版别批改了 framework 生成逻辑,不会把 bundle copy 至 framework,因而需求将 Pod 环境固定到 1.6.2;

2.pod 要支撑 binary,header ref 需求变更为#import <>或许@import以契合 moduler 规范;

3.需求一起开发环境。假设项目支撑 Swift,不同 compiler 编译产品有 Swift 版别兼容问题;

4.终究的 binary 体积比运用源码的时分大一点,不主张终究上传 Store

5.假设需求 debug 就需求切换回源码,或许通过 dSYM 映射来结束方法对定位。

6.适用于人数不多的中小型项目。一旦项目依托库较多,或许就不太适用了,束缚太多,一起对开发的要求和环境的一起性要求比较高。

2. cocoapods-imy-bin(条件需求先结束组件化)

利益:

  1. 无侵入、无影响现有的业务。
  2. 不影响未接入二进制化方案的业务团队,供应配备文件。
  3. 只需项目能编译通过就制作,即便独立组件编译失利。
  4. 支撑无二进制版别时,自动采用源码版别。
  5. 支撑只需项目能编译通过就能制作二进制组件,无需再关怀pod lint等。
  6. 支撑pod bin local 指令一键自动化制作、上传、存储项目本地现已存在的二进制组件,可合作ci打包的编译产品运用。
  7. 支撑指定依托分支、支撑:podspec =>”, :git 方法的引用
  8. 支撑一起 .a、Framework 静态库产出
  9. 支撑archive时,根据Podfile自动获取podsepc依托的库,无需强制去spec仓库拉取。
  10. 支撑多套阻隔环境,如Debug/Release/Dev配备,方便为Debug/Release/Dev各种环境供应专用二进制组件。
  11. 支撑输出.a二进制组件制作binary.podsepc无需模板。
  12. 支撑安稳的二进制组件,在上传二进制组件的binary.podsepc跳过pod lint验证,加快速度。
  13. 支撑pod bin auto 指令一键自动化制作、上传、存储单个二进制组件
  14. 支撑pod bin auto –all-make 指令一键自动化制作、上传、存储该项目下全部组件的二进制组件
  15. 支撑 是否运用二进制文件、是否制作二进制文件和二进制/源码调试功用的白名单设置
  16. 支撑pod install/update 多线程方法,加快pod进程,Pod速度提升80%+
  17. 支撑pod bin install/update 指令,结束无侵犯批改Podfile内容,避免直接批改工程的Podfile文件而导致提交冲突、误提交。
  18. 支撑pod bin code指令,结束二进制库不切换源码库、程序无需从头工作的调试才干

缺陷:

这个方案的条件是结束组件化

在施行组件私有化后,就真实结束了代码仓库阻隔,各业务线同学都会在自己的业务组件内开发,需求开发结束后将 podspec 提交到私有源,壳工程实行 pod update 即可将新开发的业务组件更新下来,就可以直接打包提测了。其实组件拆分算得上是体力活,但这是二进制的根底,这个结构搭欠好二进制将无从谈起。

单私有源方案

iOS编译速度优化实践

二进制现在商场上有单私有源、双私有源两种可行方案,下面临这两种方案进行下简略的阐明:

单私有源指的是只需一个装 podspec 的私有仓库,也便是上面图中的 PrivateRepo 仓库。那么一个仓库怎样结束源码与二进制的切换呢?其实也很简略,通过在 podspec 配备环境变量即可,总结有如下几步:

  1. 在 Class 同级目录下创建 Lib 文件夹,将二进制 framework 复制其间,并推送至远程仓库
**├── Assets**
**│ └── Media.xcassets**
**│   ├── Contents.json**
**│   └── cb_fx.imageset**
**│     ├── Contents.json**
**├── Classes**
**│ ├── HelloWorld.h**
**│ └── HelloWorld.m**
**└── Lib**
**└── HelloWorld.framework**
**├── Headers -> Versions/Current/Headers**
**├── HelloWorld -> Versions/Current/HelloWorld**
**├── Resources -> Versions/Current/Resources**
**└── Versions**
**├── A**
**│ ├── Headers**
**│ │ ├── HelloWorld.h**
**│ │ ├── ClassA.h**
**│ │ ├── ClassB.h**
**│ │ └── ClassC.h**
**│ ├── HelloWorld**
**│ └── Resources**
**│   └── HelloWorld.bundle**
**│     ├── Assets.car**
**│     └── Info.plist**
**└── Current -> A**
  1. 通过环境变量,批改 podspec 的 sourcefile 指向:

**if ENV['IS_SOURCE'] || ENV["#{s.name}_SOURCE"]**
**s.source_files = "#{s.name}/Classes/**/*"**
**else**
**s.ios.vendored_frameworks = "#{s.name}/Lib/#{s.name}.framework"**
**end**
  1. 设置 preserve_paths

**s.preserve_paths = "#{s.name}/Lib/**/*.framework","#{s.name}/Classes/**/*"**

podspec 中配备 preserve_paths,确保缓存中一起存在源码和二进制的资源及文件,因为 pod 的缓存机制,假设不设置的话在源码和二进制切换时会产生文件的丢掉,导致切换时会产生不可预知的问题。

  1. 将 podspec 发布到 PrivateRepo 即可。

结束上面的配备,通过在终端输入:IS_SOURCE pod install 和 pod install 来设备源码和二进制 。假设想要某个库是源码,其他的库为二进制方法,以上图 HelloWorld 为例子,通过输入 HelloWorld_SOURCE pod install 即可让 HelloWorldrepo 为源码方法,其他的组件库为二进制方法。

尽管单私有源单版其他方案可以结束源码与二进制的转化,但是我们觉得这个方案存在以下不妥:

  1. 假设想要对多个组件进行二进制源码的切换将会非常繁琐,pod 指令因为要在终端输入 SOURCE 的原因也会变得非常长。

  2. 破坏了 pod 的缓存机制,pod 的缓存流程可以简略了解如下:

iOS编译速度优化实践

通过上面读取缓存的流程可以看出,假设组件本地只需源码的方法存在,会无法设备二进制,因为本地现已存在了就不会再去 git 上拉取二进制了。这个问题也可以处理,按照上图的思路,将一级和二级缓存删除去,这样 pod 会直接去下载 git 上的组件进行设备。

考虑到团队内不可能每个人都对这些流程很熟悉的原因,这会对我们日常作业影响较大,毕竟它对 Cocoapods 的缓存机制有所侵犯,其他跟着二进制版别增多,git 仓库也会越来越巨大,终究就有了双私有源方案。

双私有源方案

双私有源的方案是本篇的关键,cocoapods-bin 正是采用的这种方案,它指的是有两个装 podspec 的仓库,一个装源码的 podspec,例如前面说到的 PrivateRepo 仓库,另一个装二进制版其他 podspec,暂时将它起名叫 PrivateRepo_Bin,其他还需求一个静态服务器,用来存储二进制的 zip 包,供别人设备。

双私有源的方案相对单私有源来说稍凌乱些,额外需求将二进制包上传到 zip 服务器中,再生成一个二进制版其他 podspec,将其发布到二进制私有源 。让团队的全部同学都来保护二进制版其他 podspec 和二进制 zip 包无疑会严峻拖累我们的作业效率,cocoapods-bin 这类插件正是为了处理这些问题,后面会通过 cocoapods-core 源码和 cocoapods-bin 源码来剖析二进制插件的反面原理。

源码 podspec 和二进制 podspec 的大致差异如下:


{
 ...省掉
 "source": {
  "git": "https://github.com/xxx/xxx.git",
  "tag": "0.1.0",
 },
 "resource_bundles": {
  "xxx": [
   "xxx/Assets/**/*.xcassets"
  ]
 },
 "source_files": "xxx/Classes/**/*",
}
{
 ...省掉
 "source": {
  "http": "http://localhost:8080/frameworks/xxx/0.1.0/zip",
  "type": "zip"
 },
 "resources": [
  "xxx.framework/Versions/A/Resources/*.bundle"
 ],
 "ios": {
  "vendored_frameworks": "xxx.framework"
 },
}

它们首要差异在 source_files 和 vendored_frameworks,将源码的 podspec 批改一下,通过 pod repo push PrivateRepo_Bin HelloMoto.podspec 指令将其发布到 PrivateRepo_Bin 仓库。双私有源的架构图如下:

iOS编译速度优化实践

二进制

iOS 有两种类型的静态库,一种是 .a 后缀,另一种是 .framework 后缀结束,其实它们本质没有什么差异,都是被多个 .o 打包而成,只不过 .a 是一个纯二进制文件,需求合作 .h 和资源文件一起运用,.framework 内包括头文件和资源文件可以直接运用。但是引用 .framework 需求运用 <> 方法,.a 库可直接运用 “” ,具体运用那种格式可以酌情而定。

二进制打包

cocoapods-generate

cocoapods-generate 是 cocoapods-packager 作者的另一个插件,它供应了构建工程的才干,和 cocoapods-packager 比较缺失了构建 framework 功用。但它有个优点,不依托 git,可以直接根据供应的 podspec 文件在本地生成对应的工程。生成工程后,可以自界说打包脚本,运用 xcodebuild 相关指令构建对应二进制。开发 Cocoapods Plugin 的时分,配备上 Gemfile 依托即可运用 cocoapods-generate:

group :debug do
  gem 'ruby-debug-ide'
  gem 'debase','0.2.5.beta1'
  gem 'rake','13.0.0'
  gem "cocoapods", '1.9.3'
  gem "cocoapods-generate",'2.0.0'
end

实行 bundle install 后,就可以直接在插件脚本内运用了:

二进制上传

二进制上传首要是配备环境:

  1. 二进制文件上传前需求先树立 mongodb 数据库,用来存储二进制相关信息,例如包名、版别等。可以直接通过 Homebrew 实行 brew install mongodb-community@4.2 设备,举荐一个 mongodb 的可视化东西:Robo 3T。
  2. 下载 binary-server 代码,在 mongodb 跑起来之后,cd 到 binary-server 下,实行 npm install 和 npm start。
  3. 终端实行上传指令(具体参看binary-server/README.md):
curl '上传url' -F "name=#{@spec.name}" -F "version=#{@spec.version}" -F "annotate=#{@spec.name}_#{@spec.version}_log" -F "file=@#{zip_file}

创建二进制 podspec

了解二进制 podspec 生成之前,需求先了解 Cocoapods 是怎样读取 podspec 文件的。在实行 pod install 后,Cocoapods 在解析依托的进程中,根据 podfile.lock 指定的版别,构建 Specification(界说在 cocoapod-core 中用来描绘 podspec 的目标) 目标。

cocoapods-core/specification.rb

def self.from_file(path, subspec_name = nil)
 #政策 .podspec 的本地途径
 path = Pathname.new(path)
 #校验 podspec 是否存在
 unless path.exist?
  raise Informative, "No podspec exists at path `#{path}`."
 end
 #文件转为 utf-8 格式字符串
 string = File.open(path, 'r:utf-8', &:read)
 # Work around for Rubinius incomplete encoding in 1.9 mode
 if string.respond_to?(:encoding) && string.encoding.name != 'UTF-8'
  string.encode!('UTF-8')
 end
 #实行或解析string
 from_string(string, path, subspec_name)
end

cocoapods-core/specification.rb


def self.from_string(spec_contents, path, subspec_name = nil)
 path = Pathname.new(path).expand_path
 spec = nil
 case path.extname
 #解析 .podspec
 when '.podspec'
  Dir.chdir(path.parent.directory? ? path.parent : Dir.pwd) do
   #通过 eval 实行 Pod::Specification::DSL 内界说的方法
   spec = ::Pod._eval_podspec(spec_contents, path)
   unless spec.is_a?(Specification)
    raise Informative, "Invalid podspec file at path `#{path}`."
   end
  end
 #解析 .json
 when '.json'
  #string 转为 hash 存储到 Specification 中
  spec = Specification.from_json(spec_contents)
 else
  raise Informative, "Unsupported specification format `#{path.extname}` for spec at `#{path}`."
 end
 spec.defined_in_file = path
 spec.subspec_by_name(subspec_name, true)
end

由此可以看出,podspec 文件支撑两种扩展名,podspec和json,别离以不同的方法处理。

关于二进制源码切换(美团方案)

cocoapods-imy-bin支撑源码切换和调试,具体结束原理应该和美团zsource类似

Xcode 在编译 Debug 版其他二进制进程中,在二进制中某个字段存储了该二进制所对应的源码的文件地址。当我们在 Xcode 中打断点进行调试的时分,Xcode 会根据二进制中这个字段中存储的源码文件地址,翻开对应的源码文件,并在 UI 上展现该源码文件

我们都知道苹果的 Mach-O 二进制文件运用的是DWARF这种格式来存放调试相关的数据的。但因为我们很难从这个问题中提炼几个精确的要害词在搜索引擎中检索,所以很难通过简略的几回检索就获取到我们想要的答案:二进制这个字段的称号,在初期乃至无法承认这个字段应该是从 Mach-O 的资猜中检索仍是从 DWARF 的资猜中检索。

通过实验,承认了二进制中源码文件的途径确实是用一般的字符来存储的;紧接着,我们用 MachOViewer 来检查二进制文件,以获取到更友好的二进制信息。运用 MachOViewer,我们可以发现这些信息都存在了二进制的 “__debug_str” Section 中。

iOS编译速度优化实践

iOS编译速度优化实践

iOS编译速度优化实践

AT_name

AT_comp_dir

通过实验,以及找到的这两个字段的描绘,我们基本可以承认,即便工程是运用二进制构建,只需二进制 AT_name 字段中的途径存在对应的源码文件,App 相同可以运用源码进行断点调试。这种调试方法除了批改源码再次构建不能收效以外,其他的调试场景都和直接运用源码构建无异。考虑到我们日常的调试场景绝大多数都只需求检查其他组件的源码,并不需求批改,把这个功用工程化仍是非常有意义的。

总结:

以上功用 cocoapods-imy-bin基本上都已结束,自己也在项目中运用过,但是遇到了部分库 依托的问题,导致业务库有些无法生成成功,最后只是检验在三方库结束了如上流程,也算是一个探求进程。也希望能给我们带来必定的思路和启示。,有喜好可以去研究下 cocoapods-imy-bin源码结束。

参看:

ricardo-castellanos-herreros.medium.com/speeding-up…

tech.meituan.com/2019/08/08/…

/post/690340…