Google recently announced that, starting with the next Flutter stable release, version 3.44, Swift Package Manager will replace CocoaPods in the default workflow and become the default dependency manager for iOS and macOS apps. CocoaPods’ Trunk repository will officially become read-only on December 2, 2026 — a date we already discussed in the 2024 issues of the newsletter. Still, when Flutter truly began replacing CocoaPods with SPM in its default path, it sparked widespread discussion across the community.
Many developers who have long been constrained by CocoaPods, especially those with a front-end background, greeted the news with great enthusiasm. After all, they can finally spend less time wrestling with gem install on M-series Macs, and they no longer have to face those mysterious Pods errors that always seem to appear from nowhere yet somehow manage to block the build process with surgical precision. The update even briefly turned into something of a “celebration of breaking free from Ruby.” However, because Flutter’s official switch came somewhat abruptly, many third-party plugin authors also felt anxious, as issues requesting Package.swift support quickly began pouring into numerous open-source projects.
Compared with the short-term adaptation pressure on plugin authors, the more lasting test brought by this transition lies in the reconstruction of CI/CD workflows for enterprise projects. For teams whose foundations still contain a large number of historical CocoaPods dependencies, switching to SPM smoothly and with as little pain as possible will become a major infrastructure-level challenge. Migration is not simply a matter of adding a Package.swift file locally. It means that build caches, private dependencies, binary frameworks, Xcode project generation, static and dynamic linking strategies, and multi-platform build scripts all need to be recalibrated.
This is not limited to Flutter. Given that CocoaPods has long acted as the “universal glue” between cross-platform frameworks and the native iOS ecosystem, communities such as React Native and KMP have also begun laying the groundwork for migration to SPM, while Unity-related iOS dependency resolution workflows have also started supporting SPM. Over the next period, cross-platform communities built around Apple platform build pipelines will very likely go through a painful “great migration.” It is fair to say that by 2027, SPM — a tool that has already been around for a decade — will most likely complete its “great unification” of the mainstream dependency management path across Apple platforms.
For SPM, this is undoubtedly a major victory. But we should also be clear-eyed about what this victory means. It does not mean that SPM has achieved a true breakthrough beyond its original circle. Rather, it looks more like an inward-facing victory within Apple’s native ecosystem: replacing an older solution from the Objective-C era with a modern toolchain that offers better Swift support and tighter integration with Xcode. As long as cross-platform frameworks want to deliver reliably on Apple platforms, they will ultimately find it difficult to bypass Apple’s native rules.
So where will SPM go in its next decade? Will it continue to serve as the “internal optimal solution” for Apple’s ecosystem, or will it truly step beyond the walls and compete on the same stage as tools like Cargo and npm? The answer probably does not lie in SPM itself, but in whether the Swift language can produce truly killer use cases in areas such as Linux, Android, and embedded systems.
Until that day arrives, there is one thing we can be certain of: CocoaPods’ exit is already irreversible, but SwiftPM’s story has only just turned to its second chapter.
Recent Recommendations
Deep Understanding while using LLMs
At the beginning of his SwiftUI workshops, Chris Eidhof tells attendees to put LLMs aside during the exercises. The reason is not that he is against AI, but that getting an answer quickly with an LLM is not the same as truly understanding the problem. The core of this article is an increasingly visible phenomenon in the age of AI-assisted programming: more and more developers are falling into “shallow thinking.” They keep prompting, patching, and pushing features forward, while gradually losing a real understanding of the system itself. Once project complexity increases, things start to spiral out of control.
The article’s subtitle, “Solve It in 20 Minutes — Or Actually Understand It,” is not only a description of the workshop setting, but also a choice that the AI programming era places in front of developers. LLMs do not replace engineering ability; they amplify the understanding and judgment that developers already have.
Installing Swift scripts as global commands with npm
More Swift developers are starting to use Swift to write CLI tools. But during development, having to recompile after every change, manually move the binary, or maintain shell aliases can easily interrupt the iteration flow. Cristian Felipe Patiño Rojas offers a creative solution: use npm’s bin mechanism to register a Swift script with a shebang as a global command. This allows the Swift script to be invoked just like a regular CLI tool, while npm only creates a global symlink and does not participate in building the Swift code.
Considering that launching a script through
swifthas a nontrivial cold-start cost, often taking several seconds, this approach is better suited to the development stage of Swift CLI tools. For small utilities like these, developers do not necessarily need to turn them into full Swift Packages from the very beginning. Starting with the lightest possible approach, then compiling and distributing the tool once it stabilizes, is often a better fit for real-world workflows.
WatchConnectivity was failing 40% of the time. So I stopped using it.
While building real-time communication for an Apple Watch app, Tarek Sabry ran into a very frustrating problem: Apple’s official WatchConnectivity framework was unstable, with a connection success rate of only around 60%. Eventually, Tarek stopped treating WatchConnectivity as the only reliable channel and introduced a parallel network transport path instead: BLE for service discovery, HTTP for data transfer, SSE for the push channel, plus frame IDs, ack confirmation, deduplication, and retransmission. This successfully raised the connection success rate from 60% to 99%, with an almost immediate effect.
The more interesting by-product of this approach is that, because it is entirely based on standard network protocols, the Watch does not know whether the other end is an iPhone, an Android phone, or any device with an IP address. According to the author, as of April 2026, this is the only publicly available Android ↔ Apple Watch communication solution. The solution has been open-sourced under the name WatchLink, supports Swift 6, and has no third-party dependencies.
Using SwiftUI to Build a Mac-assed App in 2026
The term “Mac-assed app” describes software that truly belongs on the Mac: it uses native system controls, deeply integrates with system features, and gets every interaction detail aligned with platform conventions. While building a macOS app entirely in SwiftUI, Paulo Andrade found that although SwiftUI provides enough APIs to cover simple scenarios, the framework itself often becomes an obstacle when developers try to reproduce the interaction conventions that Mac apps have accumulated over decades.
The article breaks down several clear shortcomings of SwiftUI on macOS today: custom lists struggle to fully reproduce the subtle differences between selection, loss of focus, and right-click context targets; there is no way to detect when a context menu is open, making it difficult to correctly highlight the object the menu applies to; visibility into drag state is almost nonexistent; keyboard navigation is easily “swallowed” once a TextField has focus; and toolbar layout control is far less precise than in AppKit. Paulo argues that SwiftUI still has not completed the handoff from AppKit.
Scheduling and handling background app refresh in SwiftUI
Background refresh in iOS may look simple at the API level, but it is easy to run into pitfalls in practice. In this article, Natalia Panferova demonstrates how to configure BGAppRefreshTaskRequest with the Background Tasks framework under the SwiftUI App lifecycle, and how to register the handling logic through the backgroundTask(_:action:) scene modifier. The article walks through the full basic flow of adding background refresh to a SwiftUI app, from enabling Background Modes and registering the task identifier in Info.plist, to submitting the background refresh request and handling the app when the system wakes it. The author also explains how to simulate a background task trigger on a physical device using an Xcode debugger command, making it easier to verify the logic during development.
It is worth noting that background refresh is not a precise scheduler. Even if
earliestBeginDateis set, the system decides whether and when to wake the app based on factors such as battery level and user behavior. Therefore, critical logic should not depend on it running on time.
How to avoid Swift 6 concurrency crashes
Even with zero compile-time warnings under Swift 6 strict concurrency mode, runtime safety is not guaranteed. The compiler injects dynamic isolation assertions at actor and GCD boundaries, and if the execution path does not match the compiler’s assumptions, the app can still crash in production with _dispatch_assert_queue_fail or _swift_task_checkIsolatedSwift.
Khoa lists several common triggering scenarios: closures defined inside an @MainActor context inherit main actor isolation, and if they are later called on a background thread by old-style callback or queue-based APIs, a crash may occur; in Combine pipelines, the position of receive(on:) affects closure isolation inheritance; and if a delegate method inherits main actor isolation because the entire class is marked @MainActor, but the SDK actually calls it from an internal queue, it can also trigger a runtime assertion.
The approaches Khoa introduces in this article can help developers quickly locate and fix common runtime crash points when migrating old projects to Swift 6. However, if time and energy allow, the more ideal direction is still to reorganize feature code according to Swift 6’s modern concurrency model, make isolation boundaries explicit, and reduce reliance on local annotations and patch-style fixes.
Tools
SwiftMetalNumerics: A Swift-native GPU numerical computing library for Apple Silicon
When building real-time audio analysis or on-device signal modeling on Apple platforms, developers often get stuck in an awkward middle ground. High-level APIs such as SoundAnalysis and AVAudioEngine are convenient, but they often behave like black boxes that only provide processed results. Once you need to control STFT, frequency binning, matrix operations, or feed extracted features into custom neural network layers, you often have to bridge back and forth between Accelerate/vDSP and low-level Metal. CPU-side computation can be fast, but once the downstream computation enters the GPU pipeline, data movement and synchronization may become the bottleneck for real-time processing.
Bugra Acemoglu’s SwiftMetalNumerics is a new project aimed precisely at this middle ground. It tries to wrap Metal / MPS / MPSGraph and Accelerate / LAPACK on Apple Silicon behind Swift APIs, bringing matrix computation, FFT/STFT, convolution, and basic neural network layers into a unified numerical computing interface. What makes it interesting is not merely “GPU acceleration,” but its attempt to take advantage of the unified memory architecture to minimize back-and-forth copying between DSP, matrix computation, and lightweight ML pipelines.
SwiftMetalNumerics is not a full replacement for Accelerate. For small-scale, one-off computations, the CPU path is often still faster. But if your task is a longer real-time signal processing or on-device inference pipeline, SwiftMetalNumerics presents a direction worth watching: connecting low-level mathematical control with GPU computing power in a more Swift-native and Apple Silicon-native way.
SwiftUI Preview Runner: A SwiftUI preview engine for custom tools and AI workflows
SwiftUI Preview Runner is an inspiring experimental project developed by Aryan Rogye. It does not launch a simulator, nor does it replicate Xcode Preview’s XPC-based preview mechanism. Instead, it writes a piece of SwiftUI code into a temporary Swift Package, compiles it into a dynamic library, dynamically loads it with dlopen, and renders it inside a host macOS app using NSHostingView.
As a result, it feels more like a “SwiftUI Playground” that can be embedded into custom toolchains: you can connect an editor, AI generation, an MCP validator, or other automation workflows in front of it, allowing generated SwiftUI code to immediately enter a feedback loop of “can it compile, and can it render?”
Note that the project targets macOS SwiftUI rendering, not the iOS simulator; compilation introduces latency; and dynamically loading code also means the security boundary must be handled with great care. Even so, as an exploration of how AI-generated SwiftUI can receive real runtime feedback, it is worth paying attention to.