普通视图

发现新文章,点击刷新页面。
今天 — 2026年5月7日首页

再见吧CocoaPods,Swift Package Manager(SPM)即将在Flutter 3.44中成为默认依赖管理器

作者 JarvanMo
2026年5月7日 09:07

长久以来Futter一直以CocoaPods为作为默认的依赖管理器,而最近就在临近Google I/O了,Flutter官方却突然宣布,从下一个Flutter稳定版3.44开始,Swift Package Manager(SPM)取代CocoaPods,成为iOS和macOS应用的默认依赖管理器。

这意味你不必再为了跑通一个App而去一顿瞎折腾Ruby环境或者安装那个令人抓狂的CocoaPods了。

Flutter这么做一方面是因为SPM是Apple官方的依赖管理器,另一方面CocoaPods实际上早进入了**维护模式,并且CocoaPods trunk 明确会在 2026-12-02 进入只读**,所以今年年底 SwiftPM 就势必会完全取代 CocoaPods 这个老古董。

终于不用再忍受那蜗牛般的pod install了……

当然这个并不突然,毕竟Flutter 支持SPM这个事早就开始实施了,我自己的项目也早早已开启了SPM模式。前段时间,我自己的开源项目还收到了支持SPM的催更请求

Screenshot 2026-05-06 at 11.37.11.png

现在 Flutter 也开始正式提醒开发者,虽然现有版本还可以继续使用 CocoaPods,但是 2026-12-02 之后将不会在对 Pod 进行适配和支持 pod

那这对我们会有什么影响吗?

App 开发者

实际上,对于App开发者来说,Flutter的CLI会帮助你自动完成迁移处理。当你开始运行或构建 iOS 或 macOS 应用时,CLI 会自动更新 Xcode 项目使用全新的 Swift 包管理器。

如果 App 依赖的插件还没适配 SwiftPM,Flutter 会打印一条警告信息,列出所有不受支持的依赖项,同时暂时回退到 CocoaPods

当然这种回退并不会长久,毕竟Cocoapods都即将寿终正寝了,SPM又是Apple的太子,对Cocoapods的支持完全移除也在情理之中了。

当然,如果你真的遇到了SPM导致的构建问题,官方也提供了临时解决方案:

flutter:  
 config:  
   enable-swift-package-manager: false

pubspec.yaml中把SPM关掉就好了。

插件开发者

对于插件开发者,如果你的插件支持iOS/macOS,那你是逃不开了(我不会告诉你fluwx/tobias spm适配进展缓慢)。Flutter社区其实一直在推进插件对SPM的适配(比如我就收到了适配请求),目前排名前 100 的 iOS 插件里已经有 61% 完成了迁移,后续如果没添加 Swift Package Manager 支持的 Package ,在 pub.dev 评分中得分也会被拉低。

其实是SPM与CocoaPods是非常非常不同的,这也是导致Fluwx/Tobias等项目的SPM支持进展缓慢的原因,比如说在使用CocoaPods时,podspec可以在pod install的时候作为Ruby脚本执行,即可以入侵你的Flutter项目构建过程,fluwx中的no_pay就是基于该原理实现的。而SPM虽然也是可执行的 Swift 脚本,但 SPM 在 swift package resolve 阶段就锁定了依赖图,这个阶段与 Flutter 构建流程完全解耦,无法可靠地从外部注入状态,这就导致我们无法像cocoapods那样通过在pubspec.yaml切换到no_pay状态,这意味我们又要把fluwx拆分成双包即fluwxfluwx_no_pay

且不提我的项目问题,说回SPM和CocoaPods的迁移问题。

具体怎么迁移,大家可以参考Flutter migration docs for plugin authors对插件进行迁移与适配。

过往的Cocoapods就像我上面说的一样,Cocoapods已经为我们做很多了隐式的骚操作,比如:

  • 自动把 Flutter.framework 加进来
  • 自动处理 header / linker / search path
  • 不用关心 Flutter 引擎怎么进来的

但换成SwiftPM后就不一样了:

  • SwiftPM 是完全声明式依赖系统
  • 不会有 CocoaPods 那种“魔法注入”
  • 所有依赖都必须在 Package.swift 明确写出来

要知道,我们的插件代码其实是运行在 Flutter 引擎之上的,所以你需要在 Package.swift 里加这个依赖,以我正在迁移的Fluwx的Package.swift为例:

// swift-tools-version: 5.9
import PackageDescription


let package = Package(
    name: "fluwx",
    platforms: [.iOS("12.0")],
    products: [
        .library(name: "fluwx", targets: ["fluwx"])
    ],
    dependencies: [
         // 这是关键
        .package(name: "FlutterFramework", path: "../FlutterFramework"),
        .package(
            url: "https://github.com/JarvanMo/WechatOpenSDK-SPM", //
            from: "2.0.5"
        )
    ],
    targets: [
        .target(
            name: "fluwx",
            dependencies: [
                 // 这是关键
                .product(name: "FlutterFramework", package: "FlutterFramework"),
                .product(name: "WechatOpenSDK", package: "WechatOpenSDK-SPM")
            ],
            resources: [
                .process("Resources/PrivacyInfo.xcprivacy")
            ],
            cSettings: [
                .define("FLUWX_WITH_PAY"),
                .headerSearchPath("include")
            ],
            swiftSettings: [
                .define("FLUWX_WITH_PAY")
            ],
            linkerSettings: [
                .linkedFramework("CoreGraphics"),
                .linkedFramework("Security"),
                .linkedFramework("WebKit"),
                .unsafeFlags(["-ObjC", "-all_load"])
            ]
        )
    ]
)

另外如果在 2025 年做过迁移了插件,现在还也需要补充一个操作:在 Package.swift 文件中添加 FlutterFramework 作为依赖项,因为现在必须显式声明依赖。

Flutter 3.41开始,要把FlutterFramework作为一个依赖: 更新一下Package.swift以引入FlutterFramework:

dependencies: [
    .package(name: "FlutterFramework", path: "../FlutterFramework")
],
targets: [
    .target(
        // TODO: Update your target name.
        name: "plugin_name",
        dependencies: [
            .product(name: "FlutterFramework", package: "FlutterFramework")
        ],

别忘记更新 Dart/Flutter 版本

environment:
  sdk: ^3.11.0
  flutter: ">=3.41.0"

以我的切身体验来说,对 Flutter 来说这次变化影响最大的是插件生态。以前Flutter插件都是.podspec + Podfile + pod install接入,而且有不少插件会使用到魔法注入,但迁移到SPM后,这种魔法不复存在,会使一些插件的迁移难度增加。

SPM也是完全支持Objective-C 的,只是一些支持的力度和方式不太一样,比如 SwiftPM 不允许同一个 target 里同时混放 Swift 和 C-family 源码,target 可以包含 Swift、Objective-C/C++ 或 C/C++,但单个 target 不能混合 Swift 和 C-family 语言。

旧的纯OC插件/库迁移到SPM是完全可行的,只要目录结构要符合SPM规则。

真正麻烦的是那些OC+Swift混编的工程,通常来说他们要拆成多个target……

题外话

fluwx/tobais迁移到SPM的工作还在进行中, 主要就是iOS的变动,现在没了动态化的支持,很多功能变得比较麻烦。

image.png

如果大家对插件中引用本地framework可以参考我之前的文章

那么,你准备好迎接Swift Package Manager了吗?

昨天以前首页

7 个开源 iOS 应用,让你成为更好的开发者

作者 JarvanMo
2026年4月24日 10:24

多年来,我注意到开发者成长的一个规律。

教程很适合学习语法。课程有助于理解概念。但在某个阶段,最大的提升来自于阅读有经验的团队如何在真实代码库中解决真实问题。

不是示例项目,不是演示应用,而是真正上线的产品。

那种处理你根本想不到的边界情况的代码。那种经历了三年功能迭代仍然健壮的架构。那种只有亲眼看到它们在大规模下运作才能理解的决策。

我花了不少时间浏览开源 iOS 应用,以下是我认为真正值得深入研究的七个。每一个都能教会你不同的东西——关于架构、安全、设计模式,或者仅仅是良好的工程习惯。

以下是清单。

1. Firefox for iOS

仓库: mozilla-mobile/firefox-ios

许可证: MPL 2.0

这是 Mozilla 为 iOS 打造的完整浏览器,完全使用 Swift 编写。

这是一个庞大的代码库,而这正是它的价值所在。你很少有机会看到如此规模的项目如何在一个地方同时处理标签页管理、同步、遥测、内存压力和无障碍访问等问题。

最让我惊讶的是,尽管项目规模巨大,代码的可读性却相当高。Mozilla 积极标记 good first issue 工单,贡献流程文档也非常完善。

你可以学到:

  • 大规模 iOS 应用如何管理状态和内存
  • 复杂 UI 中无障碍访问的处理方式
  • 重大开源项目中的贡献流程是什么样的

如果你好奇一个生产级浏览器在底层是什么样子,这里是最好的起点。

2. Signal for iOS

仓库: signalapp/Signal-iOS

许可证: GPL-3.0

Signal 是一款注重隐私的即时通讯应用,数百万人信赖它进行安全通信。

从学习角度来看,Signal 代码库最有趣的地方在于它在每一层都极其认真地对待安全问题。端到端加密、安全本地存储、密钥管理——这些不是事后补充,而是嵌入到架构本身之中。

该应用还非常实际地混合使用了 UIKit 和 SwiftUI,这反映了当今许多生产应用的真实面貌——不是纯粹地使用其中一种,而是经过深思熟虑的混合方案。

你可以学到:

  • 安全导向的 iOS 工程模式
  • 推送通知和后台任务在真实通讯应用中如何运作
  • 团队如何在同一项目中管理 UIKit 和 SwiftUI 的共存

阅读 Signal 的代码会改变你对自己应用中数据处理的思考方式。

3. WordPress for iOS

仓库: wordpress-mobile/WordPress-iOS

许可证: GPL-2.0

这是 Automattic 官方的 WordPress 应用——最成熟的开源 iOS 项目之一。

该代码库涵盖了真正广泛的 iOS 挑战:Core Data、REST 和 GraphQL 网络请求、富文本编辑、离线同步、模块化架构。很难找到一个项目能同时涉及这么多领域。

WordPress 让我印象最深的是它的贡献体验。文档详尽,上手流程顺畅,项目周围有真正的导师文化。如果你想做出第一个有意义的开源贡献,这里是最好的起点之一。

你可以学到:

  • 生产级 Core Data 和离线优先架构
  • 如何在 iOS 上构建富文本编辑器
  • 一个成熟、维护良好的开源项目从内部看是什么样子的

4. NetNewsWire

仓库: Ranchero-Software/NetNewsWire

许可证: MIT

NetNewsWire 是一款免费的 RSS 阅读器,支持 iOS 和 macOS,由 Brent Simmons 开发。

如果你不熟悉这个名字,Brent 是 Apple 开发者社区最具影响力的元老之一。他几十年来一直在构建 Mac 和 iOS 应用,这在代码库的每一个角落都体现得淋漓尽致。

我喜欢 NetNewsWire 的地方在于它的 Swift 代码多么干净、多么地道。没有过度设计,没有不必要的抽象,只有结构良好的代码,恰好做它需要做的事。

它也是我见过的 iOS 和 macOS 之间跨平台代码共享的较好范例之一。项目规模足够小,你实际上可以通读整个代码库并理解所有部分是如何连接的。

你可以学到:

  • 地道的、干净的 Swift 在实践中是什么样子
  • 如何有效地在 iOS 和 macOS 之间共享代码
  • 经验丰富的开发者如何为长期可维护性来组织项目

如果你想从头到尾研究一个代码库,这是我推荐的仓库。

5. Wire for iOS

仓库: wireapp/wire-ios

许可证: GPL-3.0

Wire 是一款安全的即时通讯应用,支持语音通话、视频通话和群聊——全部默认加密。

对于 iOS 开发者来说,Wire 特别有趣的地方在于它的真实 WebRTC 集成。如果你好奇音频和视频通话在 iOS 代码层面到底是如何工作的,这是为数不多的能让你看到完整实现的开源项目之一。

该项目也是大规模模块化 Swift 架构的良好范例。它被拆分为边界清晰、定义明确的模块,这使得在如此规模的项目中导航比预期要容易。

你可以学到:

  • WebRTC 如何集成到原生 iOS 应用中
  • 音视频通话架构的实践
  • 如何用清晰的边界模块化大型 Swift 代码库

6. Element X for iOS

仓库: element-hq/element-x-ios

许可证: AGPL-3.0

这是下一代 Matrix 客户端,也是本列表中最现代的代码库之一。

Element X 完全使用 SwiftUI 构建,底层基于 matrix-rust-sdk。仅凭这个组合就值得研究——你能看到 SwiftUI 在生产规模下的使用,也能看到 Rust 和 Swift 如何通过 FFI 在真实应用中进行通信。

项目非常活跃,团队响应迅速,并且定期为新人标记 issue。如果你想找一个能反映 iOS 开发未来方向的项目——SwiftUI 优先,性能关键层用 Rust 编写——就是它了。

你可以学到:

  • SwiftUI 在真实生产应用中如何规模化
  • Rust 到 Swift 的 FFI 在实践中如何运作
  • SwiftUI 优先代码库中的现代架构模式

7. Kickstarter for iOS

仓库: kickstarter/ios-oss

许可证: Apache-2.0

Kickstarter 开源了他们的整个原生 iOS 应用,这是 iOS 社区中被引用最多的代码库之一。

它被广泛引用的原因在于其严谨性。函数响应式编程、MVVM 架构、依赖注入,以及真正有意义的测试覆盖率。每种模式在整个项目中都得到了一致的应用,这使它作为参考极其有用。

他们的 Pull Request 风格和代码审查文化也值得学习。从阅读他们的 PR 和提交信息中,你能学到和代码本身一样多的东西。

你可以学到:

  • 函数响应式编程在真实应用中的一致应用
  • 如何为可测试性构建依赖注入
  • 大规模下严谨的测试覆盖率到底是什么样子

如何真正用好这份清单

七个仓库确实很多。你不需要全部看完。

我的建议是:选择一个与你当前工作或好奇心相关的项目。克隆它,在 Xcode 中运行。然后挑一个功能——也许是登录流程,也许是同步层,也许是他们如何处理导航——从头到尾读一遍。

不要试图一次理解整个代码库。聚焦于一条代码路径,从 UI 层一直追踪到数据层。

你花一个下午阅读生产级代码所学到的东西,比跟着教程学一个月还要多。

如果你想做出自己的第一个开源贡献,这些项目中的大多数都会积极标记 good first issue 工单。这意味着有一个明确的入口在等着你。

最后的想法

阅读优秀的代码是一种会随时间悄然复利的好习惯。

你会开始注意到你从未想到过的模式。你会开始理解为什么某些架构决策会存在。你会培养出一种直觉——什么样的代码容易修改,什么样的代码对每一次改动都充满抗拒。

这些都不是来自某个突破性的瞬间。它们来自于持续地接触精心编写的代码,让这些模式重塑你对自己工作的思考方式。

希望这份清单能给你一个好的起点。

选一个。克隆它。开始阅读。

❌
❌