SDKs and platforms

Can I use Offline Protocol in a native Swift iOS app?

Yes. The Offline Protocol SDK ships a Swift Package Manager package, offline-protocol-swift with the product OfflineProtocolSDK, that needs no React Native and runs on iOS 13 or later. It carries the protocol engine with MLS encryption, generated Swift bindings and the Bluetooth LE, relay, peer-stream, Nostr and Reticulum transport managers. It is a preview as of 0.31.0: the app wires the transports to the engine, and the storage providers are not public yet.

TL;DR

The OfflineProtocolSDK Swift package brings the Offline Protocol engine, MLS encryption, generated bindings and the iOS transport managers to a native iOS 13+ app with no React Native. It is a preview: the app wires the transports to the engine. For the complete integration today, use the React Native package.

Learning objectives

After reading this article you will be able to:

  • Add the OfflineProtocolSDK Swift package to an iOS project and check its platform limits
  • List what the Swift preview contains and what an app must still write
  • Decide between the Swift preview and the React Native package for an iPhone app

Swift package for iOS (preview)

A native Swift iOS app can use Offline Protocol through the OfflineProtocolSDK Swift package, which is a preview as of 0.31.0 (October 2026). The package lives at Offline-Protocol/offline-protocol-swift, needs no React Native, and is built from the same bridge sources the React Native module compiles. What is public in it today is what that module needed public, not a decided API, so names may change in a later release.

That status matters for planning. The Swift package is good for evaluating an integration or building on the generated bindings directly. For a phone app you ship today, the Offline Protocol docs point to the React Native package, which wires transports and storage for you.

Adding OfflineProtocolSDK with Swift Package Manager

Add the package by URL in Xcode, or in a manifest, and depend on the OfflineProtocolSDK product:

dependencies: [
    .package(url: "https://github.com/Offline-Protocol/offline-protocol-swift.git", from: "0.31.0")
],
targets: [
    .target(name: "YourApp", dependencies: [
        .product(name: "OfflineProtocolSDK", package: "offline-protocol-swift")
    ])
]

The package repository is generated by the SDK’s release workflow, which commits the assembled package and tags it with the release number. Its tags follow the SDK’s version numbers, so the package is at 0.31.0 alongside npm, PyPI, crates.io and Maven Central.

Each release checks the package before it reaches that repository. The release builds the package’s XCFramework from its own archives, assembles the package around it, and runs every test suite plus a consumer check, a separate package that depends on it the way an application would, on an iOS simulator. The distribution repository’s workflow then verifies the release assets’ attestations before it commits and tags the package, and a tag never moves once written. The same GitHub release also attaches the XCFramework (offline-protocol-X.Y.Z-swiftpm-xcframework.zip) and the assembled package (offline-protocol-X.Y.Z-swift-package.tar.gz).

iOS 13 and iOS-only requirements

The Swift package requires iOS 13.0 or later and is iOS only: the binary has no macOS or Mac Catalyst slice. The Rust library ships as an XCFramework with device and simulator slices, so you can build for both.

On a Mac, the package is not an option. A desktop or server tool on Apple silicon can use the Python package instead, and What platforms does Offline Protocol support? lists the rest.

Contents of the Swift package

The Swift package carries the engine and the iOS transport code, but not yet the glue between them:

PartWhat it is
offline_protocolFFIThe Rust library, as an XCFramework for device and simulator
Generated bindingsOfflineProtocol, ProtocolConfig, MeshServices, DataStore and the rest of the API, generated from the Rust interface
TransportsThe Bluetooth LE, internet relay, peer-stream, Nostr and Reticulum managers, the same sources the React Native module compiles
StorageThe Keychain store for MLS material and the file store for protocol state, not yet public

The Rust core inside is an I/O-free engine. It queues, routes and encrypts, and never opens a socket or touches a radio for the protocol. Each transport manager does the I/O for one transport: it drains the engine’s outbound queue, sends, and hands inbound bytes back. Encryption is MLS (RFC 9420), applied automatically by the engine.

Integration steps for the Swift preview

The Swift preview gives you the engine and the transport managers, and two integration points are yours in this release:

  • Transport wiring. Connecting the managers to the engine is application code you write.
  • Storage. The Keychain MLS store and the protocol-state file store are in the package but not public yet, so an application cannot construct them today. A public entry point that sets up storage and transports together is planned as the package’s next addition.

Because the package repository is regenerated by every release, changes made there are overwritten. File issues and pull requests in the main offline-protocol-sdk repository.

iPhone transports and Info.plist keys

The iOS transport code in the package is the same code the React Native module runs, so the iOS rules carry over. The peer-stream manager uses Network framework over the local network or AWDL, and it needs NSBonjourServices with _offlineprotocol._tcp and an NSLocalNetworkUsageDescription in Info.plist, or iOS local-network privacy blocks discovery.

An iPhone and an Android phone meet over that Wi-Fi path only on a shared Wi-Fi network that allows multicast, because an iPhone cannot join an Android Wi-Fi Direct group. Bluetooth LE or the relay connects them otherwise. An iPhone on 0.28.0 or later also does not see one on 0.27 or earlier over the Wi-Fi path, because 0.27 used MultipeerConnectivity. Can a BLE app run in the background on iOS? covers the background limits any iOS Bluetooth app runs into.

Swift package or React Native

Pick React Native when you are shipping an iPhone app now and want transports, storage and encryption working together without writing the wiring. The @offline-protocol/mesh-sdk package runs on iOS 13 and later too, ships prebuilt for device and simulator, and is the stable integration.

Pick the Swift package when you want to evaluate the engine in a pure Swift codebase, build on the generated bindings directly, or track the native API as it settles. Expect to write the transport wiring and to update code when names change. The Kotlin Android preview is at the same stage on Android, and Which Offline Protocol SDK should I use? compares every binding.

Frequently asked questions

Does the Swift package need React Native?

No. You add it with Swift Package Manager, by URL in Xcode or in a Package.swift manifest, and depend on the OfflineProtocolSDK product.

Can I use the Swift package in a macOS or Mac Catalyst app?

No. The binary has no macOS or Mac Catalyst slice, so the package is iOS only. On a Mac, the Python package has a wheel for Apple silicon.

Why can't my app construct the Keychain store from the Swift package?

The storage providers, the Keychain MLS store and the protocol-state file store, are in the package but not public yet, so an application cannot construct them. A public entry point that sets up storage and transports is planned.

Where do I report a bug in the Swift package?

In the main offline-protocol-sdk repository. The offline-protocol-swift repository is generated by each release, so changes and issues filed there are not where the code is maintained.

Does the Swift package encrypt messages?

Yes. The engine inside applies end-to-end encryption with MLS (RFC 9420) automatically, as it does in the other bindings. What the preview leaves to the app is constructing storage and wiring the transports.

Sources

Build it with Offline Protocol

The native packages page shows the Swift package manifest, its requirements and contents, and the current limits of the preview.

Read the native packages docs