{"id":49021044,"url":"https://github.com/youtalk/swift-ros2","last_synced_at":"2026-05-02T02:05:05.994Z","repository":{"id":352310668,"uuid":"1207968518","full_name":"youtalk/swift-ros2","owner":"youtalk","description":"Native Swift client library for ROS 2: publish/subscribe over Zenoh or CycloneDDS without the rcl/rclcpp stack","archived":false,"fork":false,"pushed_at":"2026-05-02T00:19:04.000Z","size":231,"stargazers_count":8,"open_issues_count":10,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-02T00:25:47.347Z","etag":null,"topics":["cyclonedds","dds","geometry-msgs","ios","ipados","mac-catalyst","macos","ros","ros2","sensor-msgs","spm","swift","swift-package-manager","visionos","xcframework","zenoh","zenoh-pico"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/youtalk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-11T16:36:20.000Z","updated_at":"2026-05-02T00:17:05.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/youtalk/swift-ros2","commit_stats":null,"previous_names":["youtalk/swift-ros2"],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/youtalk/swift-ros2","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/youtalk%2Fswift-ros2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/youtalk%2Fswift-ros2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/youtalk%2Fswift-ros2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/youtalk%2Fswift-ros2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/youtalk","download_url":"https://codeload.github.com/youtalk/swift-ros2/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/youtalk%2Fswift-ros2/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32520155,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-02T01:12:54.858Z","status":"online","status_checked_at":"2026-05-02T02:00:05.923Z","response_time":132,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cyclonedds","dds","geometry-msgs","ios","ipados","mac-catalyst","macos","ros","ros2","sensor-msgs","spm","swift","swift-package-manager","visionos","xcframework","zenoh","zenoh-pico"],"created_at":"2026-04-19T04:01:25.750Z","updated_at":"2026-05-02T02:05:05.981Z","avatar_url":"https://github.com/youtalk.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# swift-ros2\n\n[![Apple CI](https://img.shields.io/github/actions/workflow/status/youtalk/swift-ros2/ci.yml?branch=main\u0026label=Apple)](https://github.com/youtalk/swift-ros2/actions/workflows/ci.yml)\n[![Linux CI](https://img.shields.io/github/actions/workflow/status/youtalk/swift-ros2/ci.yml?branch=main\u0026label=Linux)](https://github.com/youtalk/swift-ros2/actions/workflows/ci.yml)\n[![Windows CI](https://img.shields.io/github/actions/workflow/status/youtalk/swift-ros2/ci.yml?branch=main\u0026label=Windows)](https://github.com/youtalk/swift-ros2/actions/workflows/ci.yml)\n[![Android CI](https://img.shields.io/github/actions/workflow/status/youtalk/swift-ros2/ci.yml?branch=main\u0026label=Android)](https://github.com/youtalk/swift-ros2/actions/workflows/ci.yml)\n[![Latest release](https://img.shields.io/github/v/release/youtalk/swift-ros2?label=release\u0026sort=semver)](https://github.com/youtalk/swift-ros2/releases)\n[![ROS 2](https://img.shields.io/badge/ROS%202-Humble%20%7C%20Jazzy%20%7C%20Kilted%20%7C%20Rolling-22314E.svg)](https://docs.ros.org)\n[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)\n[![SPI Swift compatibility](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fyoutalk%2Fswift-ros2%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/youtalk/swift-ros2)\n[![SPI platform compatibility](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fyoutalk%2Fswift-ros2%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/youtalk/swift-ros2)\n\nNative Swift client library for ROS 2. Publish and subscribe to ROS 2 topics over **Zenoh** (via `zenoh-pico`) or **DDS** (via CycloneDDS) — without a bridge, without `rcl` / `rclcpp`, on every consumer device OS that runs Swift.\n\n\u003e The four CI badges above all reflect the same `ci.yml` workflow status (GitHub Actions does not expose per-matrix-job badges). Each label is the OS family that workflow exercises — when the badges are green, every Apple / Linux / Windows / Android matrix entry passed.\n\nShipping as **0.6.0** — Apple xcframeworks (iOS / iPadOS / macOS / Mac Catalyst / visionOS), `zenoh-pico` source build on Linux / Windows / Android.\n\n## Why\n\nBringing ROS 2 to a phone, headset, or laptop usually means cross-compiling `rcl` + `rclcpp` + a DDS implementation, fighting CMake on a non-Linux host, and shipping a 100+ MB toolchain. swift-ros2 sidesteps all of that by speaking the ROS 2 wire formats directly: a SwiftPM `.package(url:)` line on Apple targets, a single `apt install ros-\u003cdistro\u003e-cyclonedds` on Linux, and a vanilla `swift build` on Windows / Android. The publisher / subscription API is Swift-native (`async`/`await`, `AsyncStream`, `Sendable`) and round-trip compatible with the `rmw_zenoh_cpp` and `rmw_cyclonedds_cpp` middlewares.\n\n## Features\n\n- **Dual transport.** `SwiftROS2Zenoh` talks to `rmw_zenoh_cpp`; `SwiftROS2DDS` talks to `rmw_cyclonedds_cpp`. Switch transports with a single `TransportConfig` change.\n- **No `rcl` dependency.** Wire-level publish / subscribe means no `rcl`, no `rclcpp`, no Python / colcon, no `rmw_*` shim layer — and no transitive build of FastDDS or CycloneDDS from source on the consumer side (Apple targets get xcframeworks; Linux gets a `pkg-config` lookup; Windows / Android stay Zenoh-only for now).\n- **Swift-native API.** `async`/`await` everywhere, `AsyncStream` subscriptions, `Sendable` conformance, structured concurrency, no opaque pointer juggling above the FFI seam.\n- **Pre-built Apple binaries.** `CZenohPico.xcframework` + `CCycloneDDS.xcframework` are attached to every GitHub Release. `swift build` downloads them in seconds — no CMake, no local bootstrap, no Apple-side codesigning dance.\n- **Source build everywhere else.** Linux, Windows, and Android compile `zenoh-pico` from `vendor/` via SwiftPM directly, each picking the matching backend (`unix` / `windows`). CycloneDDS comes from `pkg-config` on Linux. No vendored prebuilts needed.\n- **Multi-distro wire format.** Humble, Jazzy, Kilted, Rolling. Select via `ROS2Distro` on `ROS2Context`; Zenoh defaults to Jazzy when unspecified. Schema differences (e.g. `sensor_msgs/Range` gaining `variance` after Humble) are gated automatically through `isLegacySchema`.\n- **23 built-in message types** spanning `sensor_msgs`, `geometry_msgs`, `std_msgs`, `audio_common_msgs`, and `tf2_msgs`. Pure-Swift XCDR v1 encoder + decoder cover both the publish and subscribe paths.\n- **Production-proven.** Extracted from [Conduit, powered by ROS](https://apps.apple.com/app/id6757171237) — used cumulatively by **10,000+ ROS developers worldwide** and a former **#4 in the App Store's Developer Tools category**. Conduit streams 12 sensor topics from iOS / iPadOS / macOS / visionOS at up to 100 Hz over the same swift-ros2 publish path documented below.\n\n## Platforms\n\n| Platform              | Minimum target                                 | Integration path                                    | Transports     | CI job per push                       | xcframework slices built at tag time |\n|-----------------------|------------------------------------------------|-----------------------------------------------------|----------------|---------------------------------------|--------------------------------------|\n| iOS / iPadOS          | 16.0                                           | `binaryTarget` xcframework                          | Zenoh + DDS    | (covered by `build-macos` Swift compile) | `iphoneos` + `iphonesimulator`       |\n| macOS                 | 13.0                                           | `binaryTarget` xcframework                          | Zenoh + DDS    | `build-macos` (`swift build` + `swift test`) | `macosx`                             |\n| Mac Catalyst          | 16.0                                           | `binaryTarget` xcframework                          | Zenoh + DDS    | (covered by `build-macos` Swift compile) | `maccatalyst`                        |\n| visionOS              | 1.0                                            | `binaryTarget` xcframework                          | Zenoh + DDS    | (covered by `build-macos` Swift compile) | `xros` + `xrsimulator`               |\n| Linux                 | Ubuntu 22.04 / 24.04 (x86_64, aarch64)         | `zenoh-pico` source build + `pkg-config` for DDS    | Zenoh + DDS    | `build-linux` (×6: 3 distros × 2 arches)  | n/a (source build)                   |\n| Windows               | Windows 10 / 11 (x86_64)                       | `zenoh-pico` source build (Winsock + Iphlpapi)      | Zenoh only     | `build-windows`                       | n/a (source build)                   |\n| Android               | API 28+ (arm64-v8a, x86_64)                    | `zenoh-pico` source build (Bionic, unix backend)    | Zenoh only     | `build-android` (×2 ABIs)             | n/a (source build)                   |\n\nThe `build-macos` job runs `swift build` / `swift test` on `macos-15`, which compiles the Swift sources for the macOS host only — that proves the Swift code compiles against the Apple toolchain, but it does *not* drive `xcodebuild` against `iphoneos` / `iphonesimulator` / `maccatalyst` / `xros` / `xrsimulator` destinations. Those non-host Apple slices are built end-to-end only by the [`release-xcframework.yml`](.github/workflows/release-xcframework.yml) workflow at tag time, which produces the `CZenohPico.xcframework` + `CCycloneDDS.xcframework` zips attached to each GitHub release. Per-push runtime validation on iOS / visionOS / Mac Catalyst comes from [Conduit](https://apps.apple.com/app/id6757171237) — the 10K+ developer production user — rather than CI.\n\nSwift 5.9+ on Apple platforms; Linux uses Swift 6.0.2; Windows requires Swift 6.3.1 (the bundled Windows SDK shim in 6.0.x assumes older Windows Kits headers than the current `windows-latest` image ships, failing with `could not build module 'ucrt'`); Android uses the Swift 6.3.1 Android SDK from swift.org (matched against the toolchain `swift sdk install` resolves).\n\n## OS coverage at a glance\n\nROS 2 is increasingly running on consumer-grade endpoints: phones collecting sensor data, headsets running teleoperation UIs, laptops running rviz / Foxglove, SBCs inside robots. swift-ros2 ships on every major end-user device OS. By worldwide market share ([Statcounter, March 2026](https://gs.statcounter.com/os-market-share)):\n\n| Device class | Covered                                          | Not covered                | Combined share covered             |\n|--------------|--------------------------------------------------|----------------------------|------------------------------------|\n| Mobile       | iOS 32.3%, Android 67.5%                         | (KaiOS / Samsung ≈ 0.2%)   | **≈ 99.7%** of the mobile market   |\n| Desktop      | Windows 60.8%, macOS 14.8%, Linux 3.2%           | ChromeOS 1.6% (rest is Statcounter's \"Unknown\" bucket) | **≈ 78.7%** of the desktop market  |\n| XR           | visionOS                                         | Meta Quest / Pico / OpenXR-on-Android-arm not yet supported | (small market today, Apple Vision Pro install base only) |\n| All devices  | Android 37.9% + iOS 18.6% + Windows 26.3% + macOS 6.4% + Linux 1.4% | ChromeOS, KaiOS, etc.       | **≈ 90.7%** of identifiable share  |\n\nIn practice this means almost every consumer device that someone might want to attach to a ROS 2 graph — a phone publishing sensor data, a tablet running a teleoperation UI, a Windows or macOS laptop running rviz / Foxglove, a Linux SBC inside a robot — can publish and subscribe through the same SwiftPM-resolvable package.\n\n## Installation\n\n### Apple platforms (recommended)\n\n```swift\n// Package.swift\ndependencies: [\n    .package(url: \"https://github.com/youtalk/swift-ros2.git\", from: \"0.6.0\"),\n],\ntargets: [\n    .target(\n        name: \"YourApp\",\n        dependencies: [\n            .product(name: \"SwiftROS2\", package: \"swift-ros2\"),\n        ]\n    ),\n]\n```\n\n`swift build` downloads the Apple xcframework binaries that `Package.swift` pins. (The pin lags one PR behind every tag — the URL + checksums are bumped in a follow-up \"pin release URL + xcframework checksums\" PR once `release-xcframework.yml` has attached the zips and the GitHub-hosted SHA-256s exist. Practically that means a consumer who pins `from: \"X.Y.Z\"` resolves to the X.Y.Z commit and downloads whatever binaries that commit's manifest was pointing at, which is usually the previous release's; tracking `main` always picks up the latest pinned URL.) The high-level API arrives via `import SwiftROS2`, which exposes `ROS2Context` / `ROS2Node` / `ROS2Publisher` / `ROS2Subscription` and transitively links `SwiftROS2Zenoh` + `SwiftROS2DDS`. Add `SwiftROS2Zenoh` / `SwiftROS2DDS` to your target dependencies only if you want to call `ZenohClient` / `DDSClient` by name (e.g. for custom session config or test mocks) — they are *depended on* by the umbrella but not `@_exported` from it.\n\n### Linux\n\n```bash\nsudo apt install ros-jazzy-cyclonedds        # or ros-humble / ros-rolling\ngit clone --recursive https://github.com/youtalk/swift-ros2.git\ncd swift-ros2\nbash Scripts/build-linux-deps.sh             # verifies pkg-config finds CycloneDDS\n\n# Re-export in the current shell — build-linux-deps.sh sets these only inside its own subprocess.\nsource /opt/ros/jazzy/setup.bash\nexport PKG_CONFIG_PATH=/opt/ros/jazzy/lib/$(uname -m)-linux-gnu/pkgconfig:$PKG_CONFIG_PATH\n\nswift build\nswift test                                    # 69 pass, 2 LINUX_IP-gated skips\n```\n\n### Windows\n\nWindows ships Zenoh only; the DDS path is currently excluded from the Windows build graph (SwiftPM cannot orchestrate CycloneDDS's `ddsrt` CMake configure-time header generation, and no usable prebuilt path exists yet — see [Roadmap](#roadmap)).\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/youtalk/swift-ros2.git\", from: \"0.6.0\"),\n],\ntargets: [\n    .target(\n        name: \"YourApp\",\n        dependencies: [\n            .product(name: \"SwiftROS2Zenoh\", package: \"swift-ros2\"),    // umbrella isn't built on Windows\n        ]\n    ),\n]\n```\n\nRequires Swift 6.3.1. No `setup.bash` or `PKG_CONFIG_PATH` step — `swift build` handles the `zenoh-pico` source build automatically.\n\n### Android (cross-compile from macOS or Linux)\n\nInstall the Swift 6.3.1 Android SDK from [swift.org/install/android](https://www.swift.org/install/android/) (point release matched to the host Swift toolchain — CI uses 6.3.1):\n\n```bash\nswift sdk install \u003candroid-sdk-url\u003e --checksum \u003csha\u003e\nswift sdk list                                # should list aarch64-unknown-linux-android28 and x86_64-unknown-linux-android28\n```\n\nThe Android SDK's `.artifactbundle` ships `swift-resources/` and `swift-android/scripts/setup-android-sdk.sh` but no prebuilt `ndk-sysroot/`. Install Android NDK ≥ r27 (we test against r27c) and run the bundled script once to symlink the NDK sysroot into place:\n\n```bash\nANDROID_NDK_HOME=/path/to/ndk \\\n  ~/.config/swiftpm/swift-sdks/swift-*-android-*.artifactbundle/swift-android/scripts/setup-android-sdk.sh\n```\n\nCross-compile:\n\n```bash\nSWIFT_ROS2_TARGET_OS=android swift build --swift-sdk aarch64-unknown-linux-android28\n# or x86_64-unknown-linux-android28 for emulator targets\n```\n\n`SWIFT_ROS2_TARGET_OS=android` is required whenever the host OS differs from the target — both Linux → Android and macOS → Android. SwiftPM evaluates manifest-scope `#if os(...)` against the host, so without the override a Linux host would pull in the DDS path that isn't buildable for Android, and a macOS host would pick the Apple `binaryTarget` arm and never source-build `zenoh-pico` for Android at all. The variable is validated against an allow-list (`{android, apple, linux, windows}`) and any typo fails the manifest compile with a `fatalError` naming the offending value.\n\n```swift\nimport SwiftROS2Zenoh    // the SwiftROS2 umbrella isn't built on Android — same carve-out as Windows\n```\n\n## Quick Start\n\n\u003e **Windows / Android note:** the examples below use the `SwiftROS2` umbrella, which is excluded from those platforms. Use `SwiftROS2Zenoh.ZenohClient` directly for the Zenoh path; the high-level `ROS2Context` / `ROS2Node` wrappers land on Windows and Android when DDS does (see [Roadmap](#roadmap)).\n\n### Publish an IMU message over Zenoh\n\n```swift\nimport SwiftROS2\n\nlet context = try await ROS2Context(\n    transport: .zenoh(locator: \"tcp/192.168.1.100:7447\"),\n    distro: .jazzy\n)\nlet node = try await context.createNode(name: \"sensor_node\", namespace: \"/ios\")\nlet pub = try await node.createPublisher(Imu.self, topic: \"imu\")\n\nlet msg = Imu(\n    header: Header.now(frameId: \"imu_link\"),\n    linearAcceleration: Vector3(x: 0, y: 0, z: 9.81)\n)\ntry pub.publish(msg)\n```\n\n### Same thing over DDS\n\n```swift\nimport SwiftROS2\n\nlet context = try await ROS2Context(\n    transport: .ddsMulticast(domainId: 0)\n)\n// Identical Node / Publisher / Subscription API from here on.\n```\n\n### Subscribe\n\n```swift\nlet sub = try await node.createSubscription(Imu.self, topic: \"imu\")\nfor await msg in sub.messages {\n    print(\"accel: \\(msg.linearAcceleration)\")\n}\n```\n\n### Runnable examples\n\nEnd-to-end `talker` / `listener` demos modeled on `demo_nodes_cpp` — `swift run talker zenoh`, `swift run listener dds`, etc. — live under [`Sources/Examples/README.md`](Sources/Examples/README.md), with instructions for wiring them up to `ros2 topic echo` / `ros2 topic pub` on the ROS 2 side.\n\n## Module layout\n\n```\nimport SwiftROS2          // public API — re-exports CDR / Messages / Transport / Wire only\n    ├── SwiftROS2CDR        — XCDR v1 encoder + decoder (pure Swift, no deps)\n    ├── SwiftROS2Wire       — Zenoh / DDS wire codecs, ROS2Distro, TypeNameConverter\n    ├── SwiftROS2Messages   — ROS2Message protocols + 23 built-in types\n    └── SwiftROS2Transport  — TransportSession / TransportConfig / EntityManager / GIDManager\n\n// Transport modules: depended on by SwiftROS2 (so the high-level\n// ROS2Context / ROS2Node API works after `import SwiftROS2`), but\n// NOT @_exported — import them explicitly to reach ZenohClient /\n// DDSClient.\nimport SwiftROS2Zenoh      — ZenohClient (zenoh-pico FFI through CZenohBridge)\nimport SwiftROS2DDS        — DDSClient (CycloneDDS FFI through CDDSBridge)\n```\n\nThe architecture is documented in more detail under [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md).\n\n### Built-in message types\n\n- **`sensor_msgs`** (13) — `BatteryState`, `CameraInfo`, `CompressedImage`, `FluidPressure`, `Illuminance`, `Image`, `Imu`, `Joy`, `MagneticField`, `NavSatFix`, `PointCloud2`, `Range`, `Temperature`\n- **`geometry_msgs`** (3 publishable + utility types) — `PoseStamped`, `TransformStamped`, `TwistStamped`; sub-types `Vector3` / `Quaternion` / `Point` / `Pose` / `Twist` / `Transform`\n- **`std_msgs`** (5) — `BoolMsg`, `EmptyMsg`, `Float64Msg`, `Int32Msg`, `StringMsg`; plus the universal `Header`\n- **`audio_common_msgs`** (1) — `AudioData`\n- **`tf2_msgs`** (1) — `TFMessage`\n\n## Defining a custom message type\n\n```swift\nimport SwiftROS2CDR\nimport SwiftROS2Messages\n\npublic struct MyMsg: ROS2Message {\n    public static let typeInfo = ROS2MessageTypeInfo(\n        typeName: \"my_pkg/msg/MyMsg\",\n        typeHash: \"RIHS01_…\"      // get from `ros2 topic info /topic --verbose`\n    )\n\n    public var header: Header\n    public var value: Double\n\n    public func encode(to encoder: CDREncoder) throws {\n        encoder.writeEncapsulationHeader()\n        try header.encode(to: encoder)\n        encoder.writeFloat64(value)\n    }\n\n    public init(from decoder: CDRDecoder) throws {\n        self.header = try Header(from: decoder)\n        self.value = try decoder.readFloat64()\n    }\n}\n```\n\nWhen the planned [`swift-ros2-gen`](#roadmap) code generator lands, hand-written conformances like this become optional — the generator will emit the same shape from `.msg` files automatically.\n\n## Versioning\n\nTags follow Apple-ecosystem bare semver (no `v` prefix): `0.2.0`, `1.0.0-rc.1`, etc. The [release workflow](.github/workflows/release-xcframework.yml) fires on any tag matching `[0-9]*.[0-9]*.[0-9]*` (optionally `-qualifier`), builds both xcframeworks for all six Apple slices (`iphoneos`, `iphonesimulator`, `macosx`, `maccatalyst`, `xros`, `xrsimulator`), and attaches them + `.checksum` files to the GitHub release named after the tag.\n\nThe `0.x` series is pre-1.0 by design — breaking API changes are allowed between minor versions while the public surface stabilizes around the upcoming Services / Actions / `swift-ros2-gen` work (see [Roadmap](#roadmap)). 1.0.0 is gated on those landing.\n\n## Release history\n\nEach release has a corresponding [GitHub release](https://github.com/youtalk/swift-ros2/releases) with auto-generated notes; the summaries below capture the headline change.\n\n| Tag        | Date       | Headline                                                                                              |\n|------------|------------|-------------------------------------------------------------------------------------------------------|\n| **0.6.0**  | 2026-04-24 | **Android support** — arm64-v8a + x86_64 via the Swift 6.3.1 Android SDK; `zenoh-pico` source build with `ZENOH_ANDROID` (Bionic unix backend, vendored `pthread_cancel` / `_z_task_cancel` stubs); `SWIFT_ROS2_TARGET_OS` env override required for any cross-compile (allow-list-validated, fails the manifest compile on typos); `build-android` matrix (×2 ABIs) added to CI on `ubuntu-24.04` with NDK r27c. Zenoh only — DDS-on-Android tracked as future work. |\n| 0.5.0      | 2026-04-24 | **Windows x86_64 support** — three-arm `Package.swift` platform split, `zenoh-pico` source build with `ZENOH_WINDOWS` and Winsock + Iphlpapi linkage, `build-windows` job on `windows-latest` (Swift 6.3.1). Zenoh only.                                                                                              |\n| 0.4.0      | 2026-04-20 | **DDS subscriber** — `raw_cdr_serdata_from_ser` fragchain walk in `CDDSBridge`, `bridge_dds_reader_t` + listener callback, `DDSReaderHandle` / `createRawReader` / `destroyReader` on `DDSClientProtocol`, `DDSTransportSession.createSubscriber` wired through; `swift run listener dds` enabled. Minimal `talker` / `listener` example executables added. |\n| 0.3.1      | 2026-04-19 | **Hardened CDR decoder** — bounds-checks untrusted sequence + string lengths before `reserveCapacity`; fails fast on malformed null-terminated strings instead of silently dropping bytes. |\n| 0.3.0      | 2026-04-19 | **API rename (breaking)** — drop `Default` prefix from `ZenohClient` / `DDSClient`. CI matrix expanded to Linux arm64 + ROS 2 Rolling, plus Ubuntu 22.04 + ROS 2 Humble. |\n| 0.2.0      | 2026-04-18 | **Initial public release** — Publisher + Subscriber core, pure-Swift XCDR v1 encoder/decoder, Jazzy + Humble wire codecs, dual-transport (Zenoh + DDS) FFI, Apple xcframeworks via GitHub Releases, Linux source build via SwiftPM. |\n\n## Roadmap\n\nPast releases shipped roughly one breaking platform / transport / API change per week. The list below is what's queued — concrete deliverables, not aspirational vapor.\n\n### Near-term (the 1.0.0 gate)\n\n- **`swift-ros2-gen`** — code generator that takes `.msg` / `.srv` / `.action` files and emits `ROS2Message` / `ROS2Service` / `ROS2Action` Swift conformances. Goal: drop the hand-written `encode(to:)` / `init(from:)` ceremony required for every custom type today, and bring the catalog of built-in messages closer to what `rclcpp` ships out of the box.\n- **Services (request / reply)** — Zenoh: composed over `z_query_*` queryables. DDS: composed over the request-reply pattern in CycloneDDS. Public API will mirror `rcl`'s shape (`createService(_:type:handler:)` / `createClient(_:type:).call(_:)`). Additive — won't break the existing publisher / subscription API.\n- **Actions (goal / feedback / result)** — composed Services + Topics, mirroring `rcl_action`. Depends on Services landing first.\n- **Expanded message catalog** — `nav_msgs`, `visualization_msgs`, `diagnostic_msgs`, more of `geometry_msgs`. Hand-rolled until `swift-ros2-gen` ships, generated after.\n\n### Medium-term\n\n- **DDS on Windows / Android** — currently blocked on SwiftPM not orchestrating CycloneDDS's `ddsrt` CMake-configure-time header generation. Likely path: prebuilt `.artifactbundle` distribution for both targets, similar to the Apple xcframeworks but in the SPM artifact-bundle format.\n- **XCDR2 wire format** — only XCDR v1 is implemented today. XCDR v2 is required for some Rolling-era message types. Additive (new init flag on `CDRDecoder`).\n- **Richer QoS profiles** — `.servicesDefault`, `.parameters`, `.systemDefault` to match `rcl`. Today any non-default QoS knob has to be set by hand on the underlying `TransportConfig`.\n\n### Stretch\n\n- **Linux static `.artifactbundle`** — replace the `pkg-config + setup.bash` dance with a self-contained download. Prototyped and rejected for 0.5.0; might revisit once the SPM + system-library story improves.\n- **`watchOS` / `tvOS` xcframework slices** — would require `Z_FEATURE_LINK_TCP` validation under those SDKs and a `Sendable` audit for `WCSession`-style flows.\n- **OpenXR-on-Android-arm bring-up** — extends the XR coverage row above beyond visionOS once a credible runtime exists for Quest / Pico headsets.\n\n## Contributing\n\nPRs welcome. The wire-format fixtures in [`Tests/SwiftROS2WireTests/`](Tests/SwiftROS2WireTests/) and the golden CDR tests in [`Tests/SwiftROS2CDRTests/`](Tests/SwiftROS2CDRTests/) are the canonical guardrails — keep them green. [`Tests/SwiftROS2IntegrationTests/`](Tests/SwiftROS2IntegrationTests/) boots a real ROS 2 subscriber on a Linux host; set `LINUX_IP=\u003chost\u003e` locally to exercise it.\n\nLint with `swift format lint --strict --configuration .swift-format Package.swift Sources Tests` before pushing — CI fails the lint step before any of the build matrices run.\n\n## License\n\nApache License 2.0. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyoutalk%2Fswift-ros2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyoutalk%2Fswift-ros2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyoutalk%2Fswift-ros2/lists"}