- 图形学
- 移动开发
【免费下载链接】lottie-ios
An iOS library to natively render After Effects vector animations
导读
本篇技术指南围绕 lottie-ios 仓库中 Sources/Private/EmbeddedLibraries/README.md 展开,系统讲解该库在同时通过 SPM、CocoaPods、Carthage、NPM 等多种包管理器分发的前提下,为何选择将 ZipFoundation、EpoxyCore、LRUCache 三份第三方源码直接内嵌进自身工程,以及内嵌后如何更新版本、如何新增依赖、如何处理符号冲突与隐私清单。读完本文,你将完整掌握 lottie-ios 的嵌入式依赖治理方案,并能将其复用到自己的多包管理器分发项目中。
一、为什么 lottie-ios 选择"内嵌第三方库"而非"外部依赖"
lottie-ios 是一款在 iOS / macOS / tvOS / visionOS 上原生渲染 After Effects 矢量动画的库,它的分发面非常广。仓库根目录下同时存在Package.swift(SPM)、lottie-ios.podspec(CocoaPods)、Lottie.xcodeproj(Carthage/Xcode 工程)以及package.json(NPM),这意味着同一个代码库要被四套不同的打包与编译体系消费。
文档明确指出:由于这些包管理器的限制,lottie-ios 无法把 ZipFoundation、EpoxyCore、LRUCache 作为独立的模块/库去import,而是把它们的源码直接放入 Lottie 库内,作为一个整体单元编译。
这一设计决策可以从 Package.swift 中得到直接印证。SPM 目标Lottie仅声明了唯一的源码目录Sources,并且把四个 README 文档排除在编译产物之外:
.target( name: "Lottie", path: "Sources", exclude: [ "Private/EmbeddedLibraries/README.md", "Private/EmbeddedLibraries/ZipFoundation/README.md", "Private/EmbeddedLibraries/EpoxyCore/README.md", "Private/EmbeddedLibraries/LRUCache/README.md", ], resources: [.copy("PrivacyInfo.xcprivacy")], swiftSettings: [.swiftLanguageMode(.v5)] )也就是说,三份第三方源码与 lottie-ios 自身的Sources/Public、Sources/Private一起被编进同一个名为Lottie的模块,任何"额外依赖解析"都不存在,从而规避了不同包管理器对依赖图、版本约束、模块隔离的差异处理。
内嵌的三个库分别承担什么职责
| 库 | 来源版本(依各目录 README) | 在 lottie-ios 中的用途 |
|---|---|---|
| ZipFoundation | ZIPFoundation 0.9.20 | ZIP 归档的解压/读写,用于 .lottie 压缩包解析 |
| EpoxyCore | epoxy-ios 0.11.0 | Epoxy 声明式 UI 模型、SwiftUI 互操作基础设施 |
| LRUCache | LRUCache 1.0.4 | 线程安全的 LRU 缓存,用于动画与图片缓存 |
ZipFoundation 的实际调用链
.lottie格式本质上是 ZIP 压缩包,lottie-ios 在 Sources/Public/DotLottie/DotLottieFile.swift 的decompress(from:to:)中直接调用了 ZipFoundation 提供的FileManager.default.unzipItem(at:to:):
private func decompress(from url: URL, to destinationURL: URL) throws { try? FileManager.default.removeItem(at: destinationURL) try FileManager.default.createDirectory(at: destinationURL, withIntermediateDirectories: true, attributes: nil) try FileManager.default.unzipItem(at: url, to: destinationURL) try loadContent() try? FileManager.default.removeItem(at: destinationURL) try? FileManager.default.removeItem(at: url) }处理流程为:先将 .lottie 解压到临时目录 → 读取manifest.json与动画 JSON → 解析完成后再清理临时目录。同目录下还提供了decompress(data:to:)处理内存中的Data形式,先把数据写盘再走统一解压路径。
LRUCache 的三处消费场景
从源码搜索结果看,LRUCache<String, ...>被 lottie-ios 在三个缓存实现中直接使用:
- Sources/Public/AnimationCache/DefaultAnimationCache.swift:
LRUCache<String, LottieAnimation>,默认容量 100,供LottieAnimationCache.shared全局使用; - Sources/Public/DotLottie/Cache/DotLottieCache.swift:
LRUCache<String, DotLottieFile>,缓存解析后的 .lottie 文件; - Sources/Private/MainThread/LayerContainers/Utility/CachedImageProvider.swift:
LRUCache<String, CGImage>,缓存主线程渲染引擎的解码图片。
DefaultAnimationCache的源码注释还解释了选型原因:不使用NSCache,因为 NSCache 在应用进入后台时会清空全部缓存,而 LRUCache 只会在收到内存警告通知时清理,缓存命中率更高。LRUCache 实现位于 Sources/Private/EmbeddedLibraries/LRUCache/LRUCache.swift,并注册了LRUCacheMemoryWarningNotification监听系统内存压力事件。
EpoxyCore 的用途与命名冲突处理
EpoxyCore 为 lottie-ios 提供了声明式模型构建(EpoxyModelArrayBuilder、EpoxyModelStorage、各种*Providing协议)、SwiftUI 互操作(SwiftUIView、EpoxyIntrinsicContentSizeInvalidator)等基础能力,对应源码位于 Sources/Private/EmbeddedLibraries/EpoxyCore/。
内嵌最典型的问题是符号冲突:EpoxyCore 与 ZipFoundation 都有一个Entry类型。EpoxyCore 目录的 README 明确记录了处理方式——将 EpoxyCore 的Entry重命名为EpoxyEntry。该改名的落实可以从 Sources/Private/EmbeddedLibraries/EpoxyCore/Diffing/Collection+Diff.swift 看到:内部定义了一个private final class EpoxyEntry并在差量计算中引用它。
二、如何更新内嵌库:三步升级流程
当 lottie-ios 需要把某个内嵌库升级到更新的 release 时,EmbeddedLibraries/README.md 给出了严格的三步走流程,各子目录 README 也重复了同样的约定:
- 替换源码:下载目标库的最新 release,用新代码整体替换对应目录下的源码。例如升级 ZipFoundation 时,把新源码放入
Sources/Private/EmbeddedLibraries/ZipFoundation/; - 更新版本标注:把该目录 README.md 顶部的 release URL 更新为实际使用的版本。当前状态是:ZipFoundation 指向 0.9.20、EpoxyCore 指向 0.11.0、LRUCache 指向 1.0.4;
- 私有化符号:把模块中所有
public符号改为internal,防止 lottie-ios 向外部泄露任何第三方库的 API。
第 3 步是关键。以 LRUCache 为例,其源码 Sources/Private/EmbeddedLibraries/LRUCache/LRUCache.swift 中定义的是final class LRUCache<Key: Hashable, Value>而非public final class——这正是"符号内部化"的落地证据。这样即便第三方库对外暴露了与 lottie-ios 自身 API 同名的类型,也不会污染用户的调用面。
三、如何新增一个内嵌依赖:六步完整清单
文档还给出了往EmbeddedLibraries中添加全新第三方依赖的标准操作,共六步:
- 建目录:在
EmbeddedLibraries下为新的依赖创建子目录; - 登记列表:把新依赖加入本文档顶部(EmbeddedLibraries/README.md)的依赖清单;
- 写子 README:为新的库目录补一份
README.md,格式与其他依赖的 README 保持一致(即"来源版本 + 内嵌原因 + 更新说明"三段式); - 从包中排除:把新的 README.md 加入
Package.swift的exclude:列表。注意,Sources/Private/EmbeddedLibraries/README.md与三个子目录的 README 目前都已在此排除列表中,因为path: "Sources"会让 SPM 默认把Sources下所有 .md 都当作资源打包,而文档不属于编译产物; - 符号私有化:与更新流程相同,把所有
public符号改为internal; - 合并隐私清单:若新依赖自带隐私清单(Privacy Manifest),需要把其中的内容并入 lottie-ios 自己的隐私清单,即 Sources/PrivacyInfo.xcprivacy。
第 5 步在 EpoxyCore 的 README 里还有额外的补充要求:对与既有类型冲突的类型进行命名空间化(改名)。除了Entry→EpoxyEntry之外,还要删除EpoxySwiftUIHostingController.swift和EpoxySwiftUIHostingView.swift——因为 lottie-ios 不使用它们,且它们在 visionOS 构建时会发出弃用警告。这体现了一个原则:内嵌不是盲目全量拷贝,而是按需裁剪 + 消除冲突。
四、内嵌策略的取舍与适用边界
从工程实践角度归纳,lottie-ios 这套"内嵌第三方库"方案的优势与代价都很清晰:
优势
- 一份源码、四套分发(SPM / CocoaPods / Carthage / NPM)全部可用,无需处理跨包管理器的依赖传递与版本锁定;
- 整体作为一个模块编译,符号统一管理,外部使用方感知不到这些第三方库的存在(它们全部是
internal); - 通过对源码的按需裁剪(如删除未使用的 Epoxy SwiftUI Hosting 文件),可以控制最终产物体积并规避平台兼容问题。
代价与约束
- 每次上游发布新版本都需要人工同步三步流程,升级负担转移给了 lottie-ios 维护者;
- 必须持续维护改名、去重、隐私清单合并等额外工作,正如
EpoxyEntry的案例所示; - 若第三方库存在特殊构建配置或资源文件,内嵌后需要额外的适配。
因此,这套方案更适用于最终库自身就要多包管理器分发、且第三方依赖较少且稳定的场景;如果你的库只通过单一包管理器分发,通常仍应优先使用标准的dependencies:依赖声明。lottie-ios 的Package.swift目前也保留了唯一的 SPM 外部依赖airbnb/swift(供 Swift 语法规范工具链使用),说明它只在必要处使用外部依赖,能内嵌的尽量内嵌。
五、小结:以文档为纲、以源码为证的依赖治理
回顾 lottie-ios 的内嵌机制,可以提炼出四句话:
- 动机:多包管理器分发的现实约束决定了"无法 import 独立模块,只能整体编译";
- 现状:ZipFoundation(.lottie 解压)、EpoxyCore(声明式 UI / SwiftUI 互操作)、LRUCache(动画与图片 LRU 缓存)三库内嵌,版本分别锁定 0.9.20 / 0.11.0 / 1.0.4;
- 纪律:更新与新增依赖都必须遵循 README 中记录的固定流程,
public → internal与 README 排除是两条硬性要求; - 细节:命名冲突要改名(
Entry→EpoxyEntry)、无用代码要删除(EpoxySwiftUIHosting 两个文件)、隐私清单要合并(PrivacyInfo.xcprivacy)。
对于希望在自己的项目中复用该方案的读者,Sources/Private/EmbeddedLibraries/README.md 本身就是一份可迁移的 SOP 文档,配合 Package.swift 的exclude:配置与三个子目录 README 中的版本标注,即可按图索骥完成整套嵌入式依赖的引入、升级与扩展。
- 图形学
- 移动开发
【免费下载链接】lottie-ios
An iOS library to natively render After Effects vector animations
相关推荐
lottie-ios 内嵌依赖工程实践:EpoxyCore 的源码级集成与更新指南
lottie ios 内嵌依赖工程实践:EpoxyCore 的源码级集成与更新指南 导读 本指南围绕 Sources/Private/EmbeddedLibra
图形学移动开发Lottie iOS 嵌入式 LRUCache 解析:多包管理器下的第三方库内嵌策略与缓存实现原理
Lottie iOS 嵌入式 LRUCache 解析:多包管理器下的第三方库内嵌策略与缓存实现原理 本指南聚焦于 lottie ios 仓库中内嵌的 LRUCa
图形学移动开发lottie-ios 内嵌 ZIPFoundation:.lottie 文件解压的架构设计与维护指南
lottie ios 内嵌 ZIPFoundation:.lottie 文件解压的架构设计与维护指南 导读 lottie ios 的 .lottie 格式本质上
图形学移动开发
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考