Skip to content

Cocoanetics/SwiftCross

Repository files navigation

SwiftCross

SwiftCross

Swift Swift 6.2+ Platforms License

Small, dependency-free compatibility shims so the same Swift source compiles and runs on every platform the toolchain targets — Apple (macOS, iOS, tvOS, watchOS, visionOS), Linux, Windows, and Android.

The problem

A lot of convenient Foundation API only exists on Apple's Foundation, not on the open-source swift-corelibs-foundation used on Linux/Windows/Android. The moment a cross-platform package touches one of these, it stops building elsewhere:

// Compiles on Apple. On Linux: "value of type 'URLSession' has no member 'bytes'"
let (bytes, response) = try await URLSession.shared.bytes(for: request)
for try await line in bytes.lines {  }

// Compiles on Apple. On Linux: "cannot find type 'UTType' in scope"
let mime = UTType(filenameExtension: "png")?.preferredMIMEType

The usual fix is to scatter #if canImport(FoundationNetworking) shims through every project that hits the gap. SwiftCross collects those shims in one place so you write the API once and import a single module.

Approach

import SwiftCross is a drop-in replacement for import Foundation. It re-exports Foundation (plus FoundationNetworking where that's a separate module, and UniformTypeIdentifiers where it exists) and layers the shims on top. On a platform that already has the real API, SwiftCross gets out of the way and you get the native implementation; on one that doesn't, you get the shim — same call site either way.

Installation

// Package.swift
dependencies: [
    .package(url: "https://github.com/Cocoanetics/SwiftCross.git", from: "1.0.0"),
],
targets: [
    .target(name: "MyLibrary", dependencies: ["SwiftCross"]),
]
import SwiftCross   // instead of: import Foundation

What's included

URLSession.bytes(for:) / bytes(from:) + AsyncBytes

Apple's async byte-streaming API, ported to FoundationNetworking. This is a real incremental stream — a one-shot URLSession data delegate forwards chunks as they arrive and resolves the response the moment headers land, so Server-Sent Events and other long-lived responses work, not just small bodies.

let (bytes, response) = try await URLSession.shared.bytes(for: request)
for try await line in bytes.lines {
    print(line)   // streams as the server sends it, on Linux/Windows too
}

UTType

A minimal stand-in for UniformTypeIdentifiers.UTType covering the filename-extension ↔ MIME-type mapping that portable code needs.

UTType(filenameExtension: "png")?.preferredMIMEType        // "image/png"
UTType(mimeType: "application/json")?.preferredFilenameExtension  // "json"

On Apple platforms the real UTType is re-exported unchanged, so its full UTI hierarchy (conformances, supertypes, system-declared types) stays available there; the shim intentionally models only the extension/MIME surface.

ProcessInfo.localIPAddress

The machine's primary routable (non-loopback, non-link-local) IP address — something Foundation has no portable API for. A companion to the built-in, already-portable ProcessInfo.hostName (which needs no shim). Implemented on every platform: Apple / Linux / Android enumerate interfaces with getifaddrs (preferring a routable IPv4); Windows, which has no getifaddrs, opens a UDP socket and reads back the OS-selected source address with getsockname (no packet is sent).

let host = ProcessInfo.processInfo.hostName        // built-in, works everywhere
let ip   = ProcessInfo.processInfo.localIPAddress  // SwiftCross; nil if no active interface

String.Encoding(ianaCharsetName:)

Resolve an IANA charset label ("utf-8", "ISO-8859-1", "windows-1252", "shift_jis", …) to a String.Encoding, with normalization and alias folding. Uses CoreFoundation's full IANA table on Apple platforms and a built-in table elsewhere.

let data = 
let encoding = String.Encoding(ianaCharsetName: charsetFromHeader) ?? .utf8
let text = String(data: data, encoding: encoding)

Platform support

Platform Status Notes
macOS / iOS / tvOS / watchOS / visionOS ✅ build + test Native APIs re-exported
Linux ✅ build + test Primary shim target (swift-corelibs-foundation)
Windows ✅ build + test localIPAddress via a UDP socket (no getifaddrs)
Android ✅ build + test Unit tests run on the emulator (API 28)

Every platform is exercised in CI on each push.

Contributing

The bar for a shim: it should let the same source compile and run across platforms, be dependency-free, and re-export/defer to the real API where it already exists. Add the implementation under Sources/SwiftCross/, add a cross-platform test (assert behaviour that holds on both the native and shimmed paths — see Tests/SwiftCrossTests), and make sure all five CI legs stay green.

License

MIT — see LICENSE.

About

Cross-platform compatibility shims so the same Swift source compiles and runs on Apple platforms, Linux, Windows, and Android.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages