Rust nello sviluppo mobile: moduli nativi e SDK multipiattaforma

Autore: IT Sectr Pubblicato: 2026-02-11 Tempo di lettura: 10 min

Rust — un linguaggio di programmazione di sistema con garanzie di sicurezza della memoria in fase di compilazione. Sviluppato da Mozilla Research nel 2010 sotto la direzione di Graydon Hoare. Rust previene intere classi di vulnerabilità: puntatori nulli, riferimenti pendenti e race condition. Nello sviluppo mobile, Rust viene utilizzato per moduli nativi, SDK multipiattaforma e WebAssembly. Secondo Stack Overflow Survey (2025), Rust è il «linguaggio più amato» per il nono anno consecutivo.

Punti chiave

  • Rust — un linguaggio di sistema con sicurezza della memoria senza garbage collector tramite il sistema di ownership
  • Borrow checker — un analizzatore che verifica i riferimenti in fase di compilazione, prevenendo le race condition
  • Moduli nativi in Rust compilano in .so per Android e .a per iOS tramite cargo-ndk e cargo-lipo
  • WebAssembly (Wasm) permette di eseguire codice Rust nel browser e sui dispositivi mobili con prestazioni quasi native
  • FFI (Interfaccia per Funzioni Estere) — un meccanismo per chiamare Rust da Java, Kotlin e Swift tramite un ABI compatibile con C

Cos'è Rust?

Rust è un linguaggio di programmazione di sistema tipizzato staticamente con astrazioni a costo zero (zero-cost abstractions). Rust garantisce la sicurezza della memoria senza garbage collector grazie al suo sistema di ownership, borrowing e lifetimes. Il compilatore Rust è uno dei più severi: rifiuta il codice che in C++ causerebbe comportamento indefinito.

Rust compila tramite LLVM in codice nativo per tutte le architetture: ARM, x86, RISC-V, WebAssembly. Il toolkit include: rustup (installer), rustc (compilatore), cargo (gestore di pacchetti e strumento di build). Cargo.toml — analogo a package.json, contiene le dipendenze da crates.io. L'ultima versione stabile è Rust 1.81 (2025).

Aree chiave di applicazione di Rust nello sviluppo mobile: librerie native (Android NDK, iOS), SDK multipiattaforma (Firefox, Dropbox), sostituzione di C++ in sezioni critiche per le prestazioni, WebAssembly per applicazioni ibride. Google utilizza Rust in AOSP (Android Open Source Project) per i componenti Bluetooth, Wi-Fi e NFC.

Installazione e configurazione di Rust per lo sviluppo mobile

Per la cross-compilazione verso Android, sono necessari toolchain di destinazione: rustup target add aarch64-linux-android armv7-linux-androideabi. Per iOS — aarch64-apple-ios x86_64-apple-ios. cargo-ndk (per Android) e cargo-lipo (per iOS) semplificano il processo di build.

sh
# Installazione di Rust e piattaforme target per lo sviluppo mobile
$ 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

# Installazione di cargo-ndk per build Android
$ cargo install cargo-ndk

# Build per Android
$ cargo ndk -t arm64-v8a -o ./jniLibs build --release

Sistema di ownership: ownership, borrowing e lifetimes

Ownership (proprietà) è il concetto fondamentale di Rust. Ogni valore ha esattamente un proprietario. Quando viene assegnato o passato a una funzione, la proprietà viene trasferita (move). Dopo il trasferimento, il vecchio proprietario non può utilizzare il valore. Questo elimina il doppio rilascio di memoria e i puntatori pendenti.

Borrowing (prestito) consente di utilizzare temporaneamente un riferimento a un valore senza trasferirne la proprietà. Il riferimento &T (immutabile) — qualsiasi numero di lettori. Il riferimento &mut T (mutabile) — esattamente uno scrittore, nessun lettore. Il compilatore verifica queste regole in fase di compilazione.

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];  // prestito immutabile
    println!("First: {}", first);
}

process_data prende un riferimento mutabile a Vec e raddoppia ogni elemento. iter_mut() restituisce un iteratore con riferimenti mutabili. *item dereferenzia il riferimento per l'assegnazione. Dopo process_data, numbers rimane accessibile — la proprietà non è stata trasferita, solo prestata.

Lifetimes: durata dei riferimenti

Lifetimes ('a) — annotazioni che collegano le durate dei riferimenti. Il compilatore le utilizza per verificare che un riferimento non sopravviva ai dati a cui punta. Nella maggior parte dei casi, i lifetimes vengono dedotti automaticamente — è necessario specificarli solo nelle firme delle funzioni con riferimenti.

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 vive fino a questa parentesi, result è valido all'interno
    // println!("{}", result); // errore: string2 è morto
}

Rust per moduli nativi Android e iOS

Rust compila in librerie native per Android (.so tramite NDK) e iOS (.a librerie statiche). Google supporta ufficialmente Rust in Android Open Source Project (AOSP) — Rust viene utilizzato per i componenti Bluetooth (ava), DNS-over-HTTP3 e CriticalNotification. Secondo Google (2025), Rust in Android ha eliminato il 70% delle vulnerabilità di memoria nei componenti target.

Per Android si utilizza cargo-ndk, che incapsula Cargo con il toolchain corretto per l'ABI scelto. La build per Android include: aarch64-linux-android (ARM 64-bit, dispositivi moderni), armv7-linux-androideabi (ARM 32-bit), x86_64-linux-android (emulatori).

rust
// Cargo.toml — configurazione libreria per 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 — per iOS (.a), cdylib — per Android (.so). serde — serializzazione per lo scambio di dati con Kotlin/Swift. libc — tipi compatibili con C per FFI.

Esempio: elaborazione immagini in Rust

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

/// Funzione compatibile C per elaborazione immagini
#[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] disabilita il name mangling per un ABI compatibile con C. extern "C" specifica la convenzione di chiamata C. unsafe — un indicatore che la chiamata dall'esterno di Rust non garantisce sicurezza. std::ptr::copy_nonoverlapping copia i byte del risultato nel buffer di output.

SDK multipiattaforma in Rust

Rust è il candidato ideale per SDK multipiattaforma che funzionano su Android e iOS da un'unica base di codice. Aziende come Mozilla (Firefox), Dropbox (sincronizzazione file) e Meta (blockchain Libra) hanno scelto Rust per componenti critici delle loro applicazioni mobili.

Vantaggi delle librerie Rust rispetto al C++: il compilatore garantisce l'assenza di perdite di memoria e race condition nel codice multipiattaforma. Il codice scritto e testato in Rust funziona in modo identico su tutte le piattaforme. Cargo gestisce le dipendenze in modo nativo, senza CMake o vcpkg.

Libreria/CrateScopo
tonicClient/server gRPC in Rust
reqwestClient HTTP con async/await
ringCrittografia (AES, RSA, ECDSA)
sqlxSQLite e PostgreSQL asincroni
wasm-bindgenIntegrazione Rust con JavaScript/WASM
ndk-glueAndroid NativeActivity in Rust
uniffiGenerazione di binding FFI per Kotlin/Swift

Rust e WebAssembly per app mobili

Rust compila in WebAssembly (Wasm) — un formato binario eseguibile nel browser e sui dispositivi mobili. Wasm offre prestazioni quasi native nell'ambiente web. Nello sviluppo mobile, Wasm viene utilizzato in applicazioni ibride (WebView + Wasm) per calcoli complessi: rendering 3D, riconoscimento immagini, crittografia.

wasm-pack compila Rust in .wasm e genera un wrapper JS. wasm-bindgen collega le funzioni Rust con le chiamate JavaScript. Su un dispositivo mobile, l'esecutore Wasm può funzionare in WebView o tramite l'SDK Wasmer/Wasmtime.

rust
use wasm_bindgen::prelude::*;

/// Calcolo dei numeri di Fibonacci in Wasm (chiamato da 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] genera un wrapper JavaScript per la funzione fibonacci. Nel browser, la chiamata appare come wasm.fibonacci(10). I tipi u32/u64 vengono automaticamente convertiti in Number/BigInt. Il modulo Wasm pesa solo ~5 KB per una tale funzione — overhead minimo.

FFI: chiamare Rust da Kotlin e Swift

FFI (Foreign Function Interface) — un meccanismo per chiamare codice Rust da altri linguaggi. Le funzioni Rust con extern "C" e #[no_mangle] vengono esportate con un ABI compatibile con C. Da Kotlin, queste funzioni vengono chiamate tramite JNI, da Swift — tramite @_cdecl ("name") o CBridge.h.

UniFFI — uno strumento Mozilla per generare binding FFI. Si descrive l'API in un file .udl e UniFFI genera automaticamente wrapper Kotlin e Swift. Questo è l'approccio standard per i componenti Rust in Firefox Android e Firefox iOS.

rust
// Libreria Rust con interfaccia UniFFI
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> {
    // implementazione AES-256-GCM
    todo!()
}

UniFFI genera una classe Kotlin con il metodo encrypt, che accetta un ByteArray e restituisce EncryptedData. In Swift, viene creata una struct EncryptedData con i campi ciphertext (Data) e nonce (Data). Gli errori vengono convertiti in eccezioni Kotlin/Swift.

Rust vs C++: confronto per lo sviluppo mobile

Rust e C++ sono i due principali linguaggi per la programmazione di sistema nello sviluppo mobile. Entrambi compilano in codice nativo ARM e supportano FFI tramite l'ABI C. La differenza principale è il modello di sicurezza della memoria: Rust lo verifica in fase di compilazione, C++ si affida alla disciplina dello sviluppatore.

CriterioRustC++
Sicurezza memoriaGarantita (ownership)Responsabilità sviluppatore
Garbage collectorNo (RAII + ownership)No (gestione manuale)
Perdite memoriaPrevenute dal compilatorePossibili (new senza delete)
Race conditionPrevenute (Send + Sync)Possibili
Android NDKTramite cargo-ndkTramite CMake / NDK Build
Supporto iOScargo-lipo + .aXcode + .a
Sistema di buildCargo (integrato)CMake / Ninja
Tempo di build2–5 min (pulito)5–15 min (pulito)
Ecosistemacrates.io (200k+ crate)vcpkg / Conan (100k+ librerie)

Rust è più sicuro del C++ e più produttivo — il compilatore cattura errori che in C++ si manifesterebbero a runtime. Il C++ ha un ecosistema di librerie mobili più ricco. Per i nuovi progetti, Rust è preferibile; il codice C++ esistente viene portato gradualmente.

Domande frequenti

In cosa Rust differisce dal C++ per lo sviluppo mobile?

La differenza principale è la sicurezza della memoria in fase di compilazione. Rust non ha nullptr, puntatori pendenti o race condition grazie al suo sistema di ownership e borrow checker. Il C++ si affida alla disciplina dello sviluppatore, Rust si affida ai controlli del compilatore.

Si può usare Rust nello sviluppo Android?

Sì, tramite Android NDK. Google supporta ufficialmente Rust in AOSP (Android Open Source Project). Rust compila in librerie .so tramite cargo-ndk. FFI (Foreign Function Interface) tramite JNI funziona come per il C++.

Cos'è cargo e come aiuta nello sviluppo Rust?

Cargo è il gestore di pacchetti e il sistema di build di Rust. Scarica le dipendenze da crates.io, compila il progetto ed esegue i test. Nello sviluppo mobile, cargo-ndk estende Cargo per la cross-compilazione verso ABI Android.

Rust è adatto per iOS o solo per Android?

Rust supporta entrambe le piattaforme. Per iOS, cargo-lipo viene utilizzato per creare binari universali (arm64 + x86_64 simulatore). Il codice Rust compila in una libreria statica .a e viene linkato tramite Xcode.

Vale la pena imparare Rust per lo sviluppo mobile nel 2026?

Sì, Rust sta diventando lo standard per SDK multipiattaforma e moduli nativi. Google, Meta e Mozilla stanno investendo in Rust. Per i componenti critici per le prestazioni, Rust è più sicuro e produttivo del C++.

Riepilogo

  • Rust — un linguaggio di sistema con sicurezza memoria senza GC grazie a ownership, borrowing e lifetimes
  • Borrow checker previene race condition e puntatori pendenti in fase di compilazione
  • Moduli nativi vengono costruiti tramite cargo-ndk (Android .so) e cargo-lipo (iOS .a)
  • UniFFI genera binding FFI per Kotlin e Swift — lo standard Mozilla per SDK mobili
  • WebAssembly consente di eseguire Rust in WebView mobili con prestazioni quasi native
  • Google usa Rust in AOSP — vulnerabilità di memoria nei componenti target ridotte del 70%
  • Rust vs C++: Rust è più sicuro, C++ ha un ecosistema più ricco; per nuovi moduli nativi si preferisce Rust

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche