Swift Cross Platform | Cocoanetics
Privacy & Cookies: This site uses cookies. By continuing to use this website, you agree to their use.
To find out more, including how to control cookies, see here:
Cookie Policy
Ad
Cocoanetics
Our DNA is written in Swift
Youtube
RSS
Jump
Home
Blog
Our Apps
Advertise
Swift Cross Platform
by Drops on Jun 02, 2026
--><br>Jun 02, 2026
My passion for cross platform software development started around the year 2000 when I saw how a contractor at Austria’s Connect Austria – which eventually became the cellular network provider DREI – would create C++ utilities on PC with Visual Studio that then could be compiled and run in production on Compaq Tru64 Unix. I have fond memories of writing a lot of small CLI utilities the same way to solve data issues we encountered processing call record data for billing.
I always hated the approach of emulating a virtual machine to get code running of different platforms. This feels to me like watching the trojans celebrate their big wooden horse and nobody willing to listen to me shouting warnings of what ugliness might be inside.
Apple platforms and Linux share a common Unix ancestry and so it was an easy addition to compile Swift for Linux as well. Swift on Android and Windows only matured well enough quite recently so that – with the help of coding agents – we could get serious of targeting those platforms as well.
Lately I’ve discovered a new ambition: I want all open source Swift code of mine to run on the maximum diversity of platforms it can. This is possibly because GitHub grants uns OSS developers unlimited CI runs and together with my Claude that can babysit a PR all through review comments and CI failures until all platforms go green. I kept getting the same kinds of errors on those non-Apple platforms and every time my agents built yet another workaround, some hyper complete, others very sloppy.
Apple’s Foundation is generous. It ships a pile of convenience API that the open-source swift-corelibs-foundation — the Foundation you get on Linux, Windows, and Android — simply doesn’t have. The moment your code reaches for one of those conveniences, it stops compiling the instant it leaves Cupertino:
// Fine on Apple. On Linux: "value of type 'URLSession' has no member 'bytes'"<br>let (bytes, response) = try await URLSession.shared.bytes(for: request)<br>for try await line in bytes.lines { … }
// Fine on Apple. On Linux: "cannot find type 'UTType' in scope"<br>let mime = UTType(filenameExtension: "png")?.preferredMIMEType
The standard remedy is to scatter #if canImport(FoundationNetworking) through the file until the compiler stops complaining. So that’s what I did. Then I did it again in the next project. Somewhere around the third copy of the same AsyncBytes workaround, sitting in a third unrelated repo, I had the feeling every programmer knows: this is dumb, why is this not in one place?
Pulling the shims into one place
So I lifted all of them out of the individual projects and into one package. I called it SwiftCross — as in cross-platform — and gave it exactly two rules: it has no dependencies , and it must let the same Swift source compile and run on every platform the toolchain targets.
Using it is almost aggressively boring, which is the whole point:
import SwiftCross // instead of: import Foundation
import SwiftCross is a drop-in replacement for import Foundation. It re-exports Foundation (plus FoundationNetworking where that’s a separate module, plus UniformTypeIdentifiers where it exists) and layers the missing pieces on top. On a platform that already has the real API, SwiftCross steps aside and hands you the native implementation. On one that doesn’t, you get the shim — and crucially, it’s the same call site either way . The #if dances don’t vanish; they just all move inside SwiftCross, once, instead of being smeared across your own code where you have to read past them every day.
A word on the name
I have to admit the name made me grin. Swift Cross Platform Utilities, in short SwiftCross — say it out loud — sounds an awful lot like Swiss Cross. And honestly that fits better than I have any right to expect. Switzerland is the proverbial neutral ground, and that’s precisely what this package is meant to be: neutral ground between Apple’s world and everyone else’s, a place where one body of code is welcome on every platform.
So the logo became the Swiss flag — the white cross on red — except the cross isn’t solid. It’s made of Swift’s little swallow, a whole flock of them in formation. Swiss swallows. I’m far too pleased with it.
The one I actually care about: URLSession.bytes, for real this time
The shim that set all of this in motion — and still the one I’d save first if the building were on fire — is async byte streaming on URLSession.
On Apple platforms you write this and you’re done:
let (bytes, response) = try await URLSession.shared.bytes(for: request)<br>for try await line in...