Skip to main content
The Swift bindings provide native XMTP functionality for iOS and macOS applications using Mozilla’s UniFFI. These bindings expose the core LibXMTP Rust library to Swift through automatically generated FFI code.
These bindings are low-level FFI interfaces. For most iOS/macOS development, use the XMTPiOS SDK instead, which provides a Swift-native API built on top of these bindings.

Installation

The bindings are distributed as an XCFramework through Swift Package Manager:

Swift Package Manager

Add to your Package.swift:
Or in Xcode:
  1. File → Add Package Dependencies
  2. Enter repository URL: https://github.com/xmtp/libxmtp
  3. Select version and add to your target

Requirements

  • iOS 14.0+ or macOS 11.0+
  • Swift 6.1+
  • Xcode 15.0+

Architecture

The Swift bindings use UniFFI to generate Swift code from Rust, providing memory-safe cross-language communication.

Key Technologies

  • UniFFI: Mozilla’s tool for generating foreign-language bindings from Rust
  • XCFramework: Pre-compiled binary framework containing native code for all Apple platforms
  • FFI (Foreign Function Interface): Low-level interface between Swift and Rust
  • Tokio Integration: Rust async runtime with Swift async/await bridging

Binary Artifacts

The package includes two XCFramework variants:
LibXMTPSwiftFFI.xcframework - Statically linked framework (default)
  • Smaller app size when bundled
  • No runtime dependencies
  • Enabled by default trait

Object Lifetimes

UniFFI manages object lifetimes using Arc<> pointers:
  • Objects crossing the FFI boundary are wrapped in Arc<>
  • Swift ARC automatically releases Rust objects when no longer referenced
  • No manual memory management required

Async and Concurrency

The bindings use Tokio’s multi-threaded runtime:
  • Swift async/await calls map to Rust async functions
  • Rust operations may resume on different threads after await
  • All exposed objects are Send + Sync for thread safety
  • No mutable references (&mut self) across FFI boundary

Basic Usage

Here’s a basic example of creating a client and sending messages:

Development

Prerequisites

For development, you need:
  • macOS with Xcode
  • Rust toolchain
  • Cross-compilation tools for iOS targets
The easiest way is using Nix:

Build Commands

Linting and Formatting

Configuration files:
  • .swiftlint.yml - SwiftLint configuration
  • .swiftformat - SwiftFormat rules

Testing

Running Tests

Tests require a running XMTP backend:

Test Structure

Tests are located in sdks/ios/Tests/XMTPTests/:
  • ClientTests.swift - Client creation and management
  • ConversationTests.swift - Conversation operations
  • GroupTests.swift - Group messaging
  • DmTests.swift - Direct messages
  • CryptoTests.swift - Cryptographic operations

Example Test

Package Structure

From Package.swift:

Key Dependencies

  • LibXMTPSwiftFFI - FFI bindings (local XCFramework)
  • Connect - gRPC client for Swift
  • CryptoSwift - Cryptographic utilities

Advanced Patterns

Database Encryption

All local data is encrypted using a key you provide:

Environment Configuration

Inbox State Management

Streaming Updates

Performance Considerations

Memory Management

  • UniFFI uses Arc for shared ownership between Swift and Rust
  • Swift ARC automatically deallocates objects
  • Large data transfers are zero-copy where possible

Threading

  • Tokio runtime uses multiple threads for Rust operations
  • Swift async/await integrates seamlessly
  • All callbacks are Send + Sync safe

Database Performance

  • SQLite with encryption (SQLCipher)
  • Write-ahead logging (WAL) enabled
  • Connection pooling for concurrent access

Troubleshooting

Framework Not Found

If you see “Framework not found LibXMTPSwiftFFI”:

Database Errors

If you encounter database errors:

Async Context Required

Many methods require async context:

Resources

UniFFI Documentation

Learn about the UniFFI framework

Source Code

View the bindings source code

XMTPiOS SDK

Use the high-level Swift SDK

Example Tests

See real usage examples