DEV Community

Almaju
Almaju

Posted on

Building an iOS App with Rust Using UniFFI

Developing iOS applications typically involves languages like Swift or Objective-C. However, with the advent of Rust, a systems programming language known for its safety and performance, and UniFFI, an interface generator for Rust, it's now possible to create iOS apps in Rust. In this blog post, we'll guide you through the process of building a simple iOS app using Rust and UniFFI.

Prerequisites

Before we begin, ensure you have the following installed:

Step 1: Setting Up Your Rust Library

Start by creating a new Rust library.

cargo new app --lib
Enter fullscreen mode Exit fullscreen mode

Add uniffi to your Cargo.toml file:

[lib]
crate_type = ["cdylib", "staticlib"]
name = "mobile"

[dependencies]
uniffi = { version = "0.25.3", features = [ "cli" ] }
Enter fullscreen mode Exit fullscreen mode

Change your lib.rs file. Here's a basic example:

uniffi::setup_scaffolding!();

#[uniffi::export]
fn say_hi() -> String {
    "Hello from Rust!".to_string()
}
Enter fullscreen mode Exit fullscreen mode

We need uniffi-bindgen as a CLI tool.

fn main() {
    uniffi::uniffi_bindgen_main()
}
Enter fullscreen mode Exit fullscreen mode

Build the library:

cargo build
Enter fullscreen mode Exit fullscreen mode

In target/debug, you should find the libmobile.dylib file.

Generate the bindings:

cargo run --bin uniffi-bindgen generate --library ./target/debug/libmobile.dylib --language swift --out-dir ./bindings
Enter fullscreen mode Exit fullscreen mode

Step 2: Building the iOS binaries

Add these targets to Rust:

rustup target add aarch64-apple-ios-sim aarch64-apple-ios
Enter fullscreen mode Exit fullscreen mode

Build the library for Swift:

cargo build --release --target=aarch64-apple-ios-sim
cargo build --release --target=aarch64-apple-ios
Enter fullscreen mode Exit fullscreen mode

You should have two binaries target/aarch64-apple-ios-sim/release/libmobile.a and target/aarch64-apple-ios/release/libmobile.a.

Step 3: Creating the XCFramework

The XCFramework will allow us to import the library with zero effort in Xcode.

First, we need to rename the file bindings/mobileFFI.modulemap to bindings/module.modulemap.


It is important to rename the file to module.modulemap because Xcode will
not be able to find the module otherwise.

Then, we can create the XCFramework:

xcodebuild -create-xcframework \
        -library ./target/aarch64-apple-ios-sim/release/libmobile.a -headers ./bindings \
        -library ./target/aarch64-apple-ios/release/libmobile.a -headers ./bindings \
        -output "ios/Mobile.xcframework"
Enter fullscreen mode Exit fullscreen mode

Set 4: Import the library in Xcode

Create a new iOS app in Xcode.

Import both the XCFramework Mobile.xcframework and the Swift file bindings bindings/Mobile.swift files into your project (drag and drop should work).

You should be good to go!

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text(sayHi()) // <-- Here we call the Rust function
                .padding()
        }
        .padding()
    }
}
Enter fullscreen mode Exit fullscreen mode

iOS App

Putting everything together

Create a script named build-ios.sh. This script automates the process of building your Rust library for various iOS targets.

#!/bin/bash

# Build the dylib
cargo build

# Generate bindings
cargo run --bin uniffi-bindgen generate --library ./target/debug/libmobile.dylib --language swift --out-dir ./bindings

# Add the iOS targets and build
for TARGET in \
        aarch64-apple-darwin \
        aarch64-apple-ios \
        aarch64-apple-ios-sim \
        x86_64-apple-darwin \
        x86_64-apple-ios
do
    rustup target add $TARGET
    cargo build --release --target=$TARGET
done

# Rename *.modulemap to module.modulemap
mv ./bindings/mobileFFI.modulemap ./bindings/module.modulemap

# Move the Swift file to the project
rm ./ios/TodoList/Mobile.swift
mv ./bindings/mobile.swift ./ios/TodoList/Mobile.swift

# Recreate XCFramework
rm -rf "ios/Mobile.xcframework"
xcodebuild -create-xcframework \
        -library ./target/aarch64-apple-ios-sim/release/libmobile.a -headers ./bindings \
        -library ./target/aarch64-apple-ios/release/libmobile.a -headers ./bindings \
        -output "ios/Mobile.xcframework"

# Cleanup
rm -rf bindings
Enter fullscreen mode Exit fullscreen mode

See also

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.