Rust in mobile development: native modules and cross-platform SDKs

Author: IT Sectr Published: 2026-02-11 Reading time: 10 min

Rust — a systems programming language with compile-time memory safety guarantees. Developed by Mozilla Research in 2010 under the direction of Graydon Hoare. Rust prevents entire classes of vulnerabilities: null pointers, dangling references, and data races. In mobile development, Rust is used for native modules, cross-platform SDKs, and WebAssembly. According to Stack Overflow Survey (2025), Rust has been the most «loved language» for nine consecutive years.

Key Takeaways

  • Rust — a systems language with memory safety without a garbage collector via the ownership system
  • Borrow checker — an analyzer that checks references at compile time, preventing data races
  • Native modules in Rust compile to .so for Android and .a for iOS via cargo-ndk and cargo-lipo
  • WebAssembly (Wasm) allows running Rust code in the browser and on mobile devices with near-native performance
  • FFI (Foreign Function Interface) — a mechanism to call Rust from Java, Kotlin, and Swift through a C-compatible ABI

What is Rust?

Rust is a statically typed systems programming language with zero-cost abstractions. Rust guarantees memory safety without a garbage collector thanks to its ownership, borrowing, and lifetimes system. The Rust compiler is one of the strictest: it rejects code that would cause undefined behavior in C++.

Rust compiles via LLVM to native code for all architectures: ARM, x86, RISC-V, WebAssembly. The toolchain includes: rustup (installer), rustc (compiler), cargo (package manager and build tool). Cargo.toml — similar to package.json, contains dependencies from crates.io. The latest stable version is Rust 1.81 (2025).

Key application areas of Rust in mobile development: native libraries (Android NDK, iOS), cross-platform SDKs (Firefox, Dropbox), replacing C++ in performance-critical sections, WebAssembly for hybrid applications. Google uses Rust in AOSP (Android Open Source Project) for Bluetooth, Wi-Fi, and NFC components.

Installing and configuring Rust for mobile development

For cross-compilation to Android, you need target toolchains: rustup target add aarch64-linux-android armv7-linux-androideabi. For iOS — aarch64-apple-ios x86_64-apple-ios. cargo-ndk (for Android) and cargo-lipo (for iOS) simplify the build process.

sh
# Installing Rust and target platforms for mobile development
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
$ rustup target add aarch64-linux-android
$ rustup target add armv7-linux-androideabi
$ rustup target add aarch64-apple-ios
$ rustup target add x86_64-apple-ios

# Installing cargo-ndk for Android builds
$ cargo install cargo-ndk

# Building for Android
$ cargo ndk -t arm64-v8a -o ./jniLibs build --release

Ownership system: ownership, borrowing, and lifetimes

Ownership is the fundamental concept of Rust. Every value has exactly one owner. When assigned or passed to a function, ownership is moved. After a move, the previous owner cannot use the value. This eliminates double memory freeing and dangling pointers.

Borrowing allows temporary use of a reference to a value without transferring ownership. The &T reference (immutable) — any number of readers. The &mut T reference (mutable) — exactly one writer, no readers. The compiler checks these rules at compile time.

rust
fn process_data(data: &mut Vec<i32>) {
    for item in data.iter_mut() {
        *item *= 2;
    }
}

fn main() {
    let mut numbers = vec![1, 2, 3, 4, 5];
    process_data(&mut numbers);
    println!("Processed: {:?}", numbers);

    let first = &numbers[0];  // immutable borrowing
    println!("First: {}", first);
}

process_data takes a mutable reference to Vec and doubles each element. iter_mut() returns an iterator with mutable references. *item dereferences the reference for assignment. After process_data, numbers remains accessible — ownership was not moved, only borrowed.

Lifetimes: the lifetime of references

Lifetimes ('a) — annotations that link the lifetimes of references. The compiler uses them to verify that a reference does not outlive the data it points to. In most cases, lifetimes are inferred automatically — you only need to specify them in function signatures with references.

rust
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() { x } else { y }
}

fn main() {
    let string1 = String::from("rust");
    let result;
    {
        let string2 = String::from("mobile");
        result = longest(string1.as_str(), string2.as_str());
        println!("Longest: {}", result);
    } // string2 lives until this brace, result is valid inside
    // println!("{}", result); // error: string2 is dead
}

Rust for Android and iOS native modules

Rust compiles to native libraries for Android (.so via NDK) and iOS (.a static libraries). Google officially supports Rust in the Android Open Source Project (AOSP) — Rust is used for Bluetooth (ava), DNS-over-HTTP3, and CriticalNotification components. According to Google (2025), Rust in Android eliminated 70% of memory vulnerabilities in targeted components.

For Android, cargo-ndk is used, which wraps Cargo with the correct toolchain for the chosen ABI. Building for Android includes: aarch64-linux-android (64-bit ARM, modern devices), armv7-linux-androideabi (32-bit ARM), x86_64-linux-android (emulators).

rust
// Cargo.toml — library configuration for Android/iOS
[package]
name = "mobile_crypto"
version = "0.1.0"

[lib]
crate-type = ["staticlib", "cdylib"]

[dependencies]
serde = { version = "1", features = ["derive"] }
libc = "0.2"

crate-type: staticlib — for iOS (.a), cdylib — for Android (.so). serde — serialization for data exchange with Kotlin/Swift. libc — C-compatible types for FFI.

Example: image processing in Rust

rust
use std::ffi::{CStr, CString};
use std::os::raw::c_char;

/// C-compatible function for image processing
#[no_mangle]
pub unsafe extern "C" fn process_image(
    input: *const u8,
    len: usize,
    output: *mut u8,
    out_len: *mut usize,
) {
    let input_slice = std::slice::from_raw_parts(input, len);
    let result: Vec<u8> = input_slice.iter()
        .map(|b| b ^ 0xFF)
        .collect();
    let result_len = result.len();
    std::ptr::copy_nonoverlapping(result.as_ptr(), output, result_len);
    *out_len = result_len;
}

#[no_mangle] disables name mangling for C-compatible ABI. extern "C" specifies the C calling convention. unsafe — a marker indicating that a call from outside Rust does not guarantee safety. std::ptr::copy_nonoverlapping copies result bytes to the output buffer.

Cross-platform SDKs in Rust

Rust is the ideal candidate for cross-platform SDKs that work on Android and iOS from a single codebase. Companies like Mozilla (Firefox), Dropbox (file synchronization), and Meta (Libra blockchain) chose Rust for critical components of their mobile applications.

Advantages of Rust libraries over C++: the compiler guarantees the absence of memory leaks and data races in cross-platform code. Code written and tested in Rust once works identically on all platforms. Cargo manages dependencies natively, without CMake or vcpkg.

Library/CratePurpose
tonicgRPC client/server in Rust
reqwestHTTP client with async/await
ringCryptography (AES, RSA, ECDSA)
sqlxAsync SQLite, PostgreSQL
wasm-bindgenRust-to-JavaScript/WASM integration
ndk-glueAndroid NativeActivity in Rust
uniffiFFI binding generation for Kotlin/Swift

Rust and WebAssembly for mobile apps

Rust compiles to WebAssembly (Wasm) — a binary format executable in the browser and on mobile devices. Wasm delivers near-native performance in web environments. In mobile development, Wasm is used in hybrid applications (WebView + Wasm) for complex computations: 3D rendering, image recognition, encryption.

wasm-pack compiles Rust to .wasm and generates a JS wrapper. wasm-bindgen connects Rust functions with JavaScript calls. On a mobile device, the Wasm runner can run in WebView or via the Wasmer/Wasmtime SDK.

rust
use wasm_bindgen::prelude::*;

/// Computing Fibonacci numbers in Wasm (called from JS)
#[wasm_bindgen]
pub fn fibonacci(n: u32) -> u64 {
    match n {
        0 => 0,
        1 => 1,
        _ => {
            let mut a = 0;
            let mut b = 1;
            for _ in 2..=n {
                let temp = a + b;
                a = b;
                b = temp;
            }
            b
        }
    }
}

#[wasm_bindgen] generates a JavaScript wrapper for the fibonacci function. In the browser, the call looks like wasm.fibonacci(10). Types u32/u64 are automatically converted to Number/BigInt. The Wasm module weighs only ~5 KB for such a function — minimal overhead.

FFI: Calling Rust from Kotlin and Swift

FFI (Foreign Function Interface) — a mechanism for calling Rust code from other languages. Rust functions with extern "C" and #[no_mangle] are exported with a C-compatible ABI. From Kotlin, such functions are called via JNI, from Swift — via @_cdecl ("name") or CBridge.h.

UniFFI — a Mozilla tool for generating FFI bindings. You describe the API in a .udl file, and UniFFI generates Kotlin and Swift wrappers automatically. This is the standard approach for Rust components in Firefox Android and Firefox iOS.

rust
// Rust library with UniFFI interface
uniffi::setup_scaffolding!();

#[derive(uniffi::Enum)]
pub enum EncryptionError {
    InvalidKey,
    EncryptionFailed,
}

#[derive(uniffi::Record)]
pub struct EncryptedData {
    pub ciphertext: Vec<u8>,
    pub nonce: Vec<u8>,
}

#[uniffi::export]
pub fn encrypt(key: &[u8], plaintext: &[u8]) -> Result<EncryptedData, EncryptionError> {
    // AES-256-GCM implementation
    todo!()
}

UniFFI generates a Kotlin class with the encrypt method, which takes a ByteArray and returns EncryptedData. In Swift, an EncryptedData struct is created with fields ciphertext (Data) and nonce (Data). Errors are converted to Kotlin/Swift exceptions.

Rust vs C++: comparison for mobile development

Rust and C++ are the two main languages for systems programming in mobile development. Both compile to native ARM code and support FFI via the C ABI. The key difference is the memory safety model: Rust checks it at compile time, C++ relies on developer discipline.

CriterionRustC++
Memory safetyGuaranteed (ownership)Developer responsibility
Garbage collectorNo (RAII + ownership)No (manual management)
Memory leaksPrevented by compilerPossible (new without delete)
Data racesPrevented (Send + Sync)Possible
Android NDKVia cargo-ndkVia CMake / NDK Build
iOS supportcargo-lipo + .aXcode + .a
Build systemCargo (built-in)CMake / Ninja
Build time2–5 min (clean)5–15 min (clean)
Ecosystemcrates.io (200k+ crates)vcpkg / Conan (100k+ libraries)

Rust is safer than C++ and more productive — the compiler catches errors that would manifest at runtime in C++. C++ has a richer mobile library ecosystem. For new projects, Rust is preferable; existing C++ code is ported incrementally.

Frequently Asked Questions

How is Rust different from C++ for mobile development?

The main difference is compile-time memory safety. Rust has no nullptr, dangling pointers, or data races thanks to its ownership system and borrow checker. C++ relies on developer discipline, Rust relies on compiler checks.

Can Rust be used in Android development?

Yes, via Android NDK. Google officially supports Rust in AOSP (Android Open Source Project). Rust compiles to .so libraries via cargo-ndk. FFI (Foreign Function Interface) through JNI works the same way as for C++.

What is cargo and how does it help in Rust development?

Cargo is Rust's package manager and build system. It downloads dependencies from crates.io, compiles the project, and runs tests. In mobile development, cargo-ndk extends Cargo for cross-compilation to Android ABIs.

Is Rust suitable for iOS or just Android?

Rust supports both platforms. For iOS, cargo-lipo is used to create universal binaries (arm64 + x86_64 simulator). Rust code compiles to a static .a library and links via Xcode.

Should I learn Rust for mobile development in 2026?

Yes, Rust is becoming the standard for cross-platform SDKs and native modules. Google, Meta, and Mozilla are investing in Rust. For performance-critical components, Rust is safer and more productive than C++.

Summary

  • Rust — a systems language with memory safety without GC thanks to ownership, borrowing, and lifetimes
  • Borrow checker prevents data races and dangling pointers at compile time
  • Native modules are built via cargo-ndk (Android .so) and cargo-lipo (iOS .a)
  • UniFFI generates FFI bindings for Kotlin and Swift — the Mozilla standard for mobile SDKs
  • WebAssembly enables running Rust in mobile WebViews with near-native performance
  • Google uses Rust in AOSP — memory vulnerabilities in targeted components reduced by 70%
  • Rust vs C++: Rust is safer, C++ has a richer ecosystem; for new native modules, Rust is preferred

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also