Rust w programowaniu mobilnym: moduły natywne i wieloplatformowe SDK

Autor: IT Sectr Opublikowano: 2026-02-11 Czas czytania: 10 min

Rust — systemowy język programowania z gwarancjami bezpieczeństwa pamięci na etapie kompilacji. Opracowany przez Mozilla Research w 2010 roku pod kierownictwem Graydona Hoare'a. Rust zapobiega całym klasom podatności: wskaźnikom null, zwisającym referencjom i wyścigom danych. W programowaniu mobilnym Rust jest używany do modułów natywnych, wieloplatformowych SDK i WebAssembly. Według danych Stack Overflow Survey (2025), Rust zajmuje pierwsze miejsce jako „ulubiony język” dziewiąty rok z rzędu.

Najważniejsze

  • Rust — język systemowy z bezpieczeństwem pamięci bez garbage collectora dzięki systemowi własności (ownership)
  • Borrow checker — analizator pożyczania, sprawdzający referencje na etapie kompilacji, zapobiegając wyścigom danych
  • Moduły natywne w Rust kompilują się do .so dla Androida i .a dla iOS przez cargo-ndk i cargo-lipo
  • WebAssembly (Wasm) umożliwia uruchamianie kodu Rust w przeglądarce i na urządzeniach mobilnych z wydajnością near-native
  • FFI (Foreign Function Interface) — mechanizm wywoływania Rust z Java, Kotlin i Swift przez C-kompatybilny ABI

Czym jest Rust?

Rust — statycznie typowany język programowania systemowego z zerową abstrakcją (zero-cost abstractions). Rust gwarantuje bezpieczeństwo pamięci bez garbage collectora dzięki systemowi własności (ownership), pożyczania (borrowing) i czasów życia (lifetimes). Kompilator Rust jest jednym z najsurowszych — odrzuca kod, który w C++ spowodowałby niezdefiniowane zachowanie.

Rust kompiluje się przez LLVM do kodu natywnego dla wszystkich architektur: ARM, x86, RISC-V, WebAssembly. Narzędzia: rustup (instalator), rustc (kompilator), cargo (menedżer pakietów i narzędzie budowania). cargo.toml — odpowiednik package.json, zawiera zależności z crates.io. Aktualna wersja — Rust 1.81 (2025).

Kluczowe obszary zastosowania Rust w programowaniu mobilnym: biblioteki natywne (Android NDK, iOS), wieloplatformowe SDK (Firefox, Dropbox), zastąpienie C++ w sekcjach performance-critical, WebAssembly dla aplikacji hybrydowych. Google używa Rust w AOSP (Android Open Source Project) dla komponentów Bluetooth, Wi-Fi i NFC.

Instalacja i konfiguracja Rust dla programowania mobilnego

Do cross-kompilacji pod Android potrzebne są docelowe toolchainy: rustup target add aarch64-linux-android armv7-linux-androideabi. Dla iOS — aarch64-apple-ios x86_64-apple-ios. cargo-ndk (dla Androida) i cargo-lipo (dla iOS) upraszczają budowanie.

sh
# Instalacja Rust i docelowych platform dla programowania mobilnego
$ 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

# Instalacja cargo-ndk dla budowania pod Android
$ cargo install cargo-ndk

# Budowanie pod Android
$ cargo ndk -t arm64-v8a -o ./jniLibs build --release

System własności: ownership, borrowing i lifetimes

Ownership (własność) — fundamentalne pojęcie Rust. Każda wartość ma dokładnie jednego właściciela. Przy przypisaniu lub przekazaniu do funkcji własność jest przenoszona (move). Po przeniesieniu stary właściciel nie może używać wartości. Eliminuje to podwójne zwalnianie pamięci i zwisające wskaźniki.

Borrowing (pożyczanie) umożliwia tymczasowe użycie referencji do wartości bez przenoszenia własności. Referencja &T (immutowalna) — dowolna liczba czytelników. Referencja &mut T (mutowalna) — dokładnie jeden pisarz, bez czytelników. Kompilator sprawdza te reguły na etapie budowania.

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!("Przetworzone: {:?}", numbers);

    let first = &numbers[0];  // pożyczenie immutowalne
    println!("Pierwszy: {}", first);
}

process_data przyjmuje mutowalną referencję do Vec i podwaja każdy element. iter_mut() zwraca iterator z mutowalnymi referencjami. *item dereferencuje referencję do przypisania. Po process_data numbers pozostaje dostępny — własność nie została przeniesiona, tylko pożyczona.

Lifetimes: czas życia referencji

Lifetimes ('a) — adnotacje do wiązania czasów życia referencji. Kompilator używa ich do sprawdzenia, czy referencja nie przeżywa danych, na które wskazuje. W większości przypadków lifetimes są wyprowadzane automatycznie — należy je podawać tylko w sygnaturach funkcji z referencjami.

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!("Najdłuższy: {}", result);
    } // string2 żyje do tego nawiasu, result jest ważny wewnątrz
    // println!("{}", result); // błąd: string2 umarł
}

Rust dla modułów natywnych Android i iOS

Rust kompiluje się do bibliotek natywnych dla Androida (.so przez NDK) i iOS (.a biblioteki statyczne). Google oficjalnie wspiera Rust w Android Open Source Project (AOSP) — w Rust napisano komponenty Bluetooth (ava), DNS-over-HTTP3 i CriticalNotification. Według Google (2025), Rust w Android wyeliminował 70% podatności pamięci w docelowych komponentach.

Dla Androida używany jest cargo-ndk, który opakowuje Cargo z odpowiednim toolchainem dla wybranego ABI. Budowanie pod Android obejmuje: aarch64-linux-android (64-bit ARM, nowoczesne urządzenia), armv7-linux-androideabi (32-bit ARM), x86_64-linux-android (emulatory).

rust
// Cargo.toml — konfiguracja biblioteki dla 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 — dla iOS (.a), cdylib — dla Androida (.so). serde — serializacja do wymiany danych z Kotlin/Swift. libc — typy C-kompatybilne dla FFI.

Przykład: przetwarzanie obrazu w Rust

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

/// Funkcja C-kompatybilna do przetwarzania obrazu
#[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] wyłącza name mangling dla C-kompatybilnego ABI. extern "C" ustawia konwencję wywoływania C. unsafe — znacznik, że wywołanie spoza Rust nie gwarantuje bezpieczeństwa. std::ptr::copy_nonoverlapping kopiuje bajty wyniku do bufora wyjściowego.

Wieloplatformowe SDK w Rust

Rust — idealny kandydat na wieloplatformowe SDK działające na Android i iOS z jednej bazy kodu. Firmy Mozilla (Firefox), Dropbox (synchronizacja plików) i Meta (Libra blockchain) wybrały Rust do krytycznych komponentów swoich aplikacji mobilnych.

Zalety biblioteki Rust w porównaniu z C++: kompilator gwarantuje brak wycieków pamięci i wyścigów danych w kodzie wieloplatformowym. Kod w Rust napisany raz i przetestowany działa identycznie na wszystkich platformach. Cargo zarządza zależnościami natywnie, bez CMake i vcpkg.

Biblioteka/KrataPrzeznaczenie
tonicgRPC klient/serwer w Rust
reqwestKlient HTTP z async/await
ringKryptografia (AES, RSA, ECDSA)
sqlxAsynchroniczna praca z SQLite, PostgreSQL
wasm-bindgenIntegracja Rust z JavaScript/WASM
ndk-glueAndroid NativeActivity w Rust
uniffiGenerowanie wiązań FFI dla Kotlin/Swift

Rust i WebAssembly dla aplikacji mobilnych

Rust kompiluje się do WebAssembly (Wasm) — formatu binarnego wykonywalnego w przeglądarce i na urządzeniach mobilnych. Wasm zapewnia wydajność near-native w środowisku webowym. W programowaniu mobilnym Wasm jest używany w aplikacjach hybrydowych (WebView + Wasm) do złożonych obliczeń: renderowanie 3D, rozpoznawanie obrazów, szyfrowanie.

wasm-pack kompiluje Rust do .wasm i generuje opakowanie JS. wasm-bindgen łączy funkcje Rust z wywołaniami JavaScript. Na urządzeniu mobilnym Wasm-runner może działać w WebView lub przez SDK Wasmer/Wasmtime.

rust
use wasm_bindgen::prelude::*;

/// Obliczanie liczby Fibonacciego w Wasm (wywoływane z 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] generuje opakowanie JavaScript dla funkcji fibonacci. W przeglądarce wywołanie wygląda jak wasm.fibonacci(10). Typy u32/u64 są automatycznie konwertowane na Number/BigInt. Moduł Wasm waży ~5 KB dla takiej funkcji — minimalny narzut.

FFI: wywoływanie Rust z Kotlin i Swift

FFI (Foreign Function Interface) — mechanizm wywoływania kodu Rust z innych języków. Funkcje Rust z extern "C" i #[no_mangle] są eksportowane z C-kompatybilnym ABI. Z Kotlin takie funkcje są wywoływane przez JNI, ze Swift — przez @_cdecl ("name") lub CBridge.h.

UniFFI — narzędzie Mozilla do generowania wiązań FFI. Opisujesz API w pliku .udl, UniFFI generuje opakowania Kotlin i Swift automatycznie. To standardowe podejście dla komponentów Rust w Firefox Android i Firefox iOS.

rust
// Biblioteka Rust z interfejsem 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> {
    // implementacja AES-256-GCM
    todo!()
}

UniFFI generuje klasę Kotlin z metodą encrypt, przyjmującą ByteArray i zwracającą EncryptedData. W Swift tworzona jest struktura EncryptedData z polami ciphertext (Data) i nonce (Data). Błędy są przekształcane w wyjątki Kotlin/Swift.

Rust kontra C++: porównanie dla programowania mobilnego

Rust i C++ — dwa główne języki programowania systemowego w programowaniu mobilnym. Oba kompilują się do kodu natywnego dla ARM i obsługują FFI przez C ABI. Główna różnica — model bezpieczeństwa pamięci: Rust sprawdza go na etapie kompilacji, C++ polega na dyscyplinie programisty.

KryteriumRustC++
Bezpieczeństwo pamięciGwarantowane (ownership)Odpowiedzialność programisty
Garbage collectorNie (RAII + ownership)Nie (ręczne zarządzanie)
Wycieki pamięciZapobiegane przez kompilatorMożliwe (new bez delete)
Wyścigi danychZapobiegane (Send + Sync)Możliwe
Android NDKPrzez cargo-ndkPrzez CMake / NDK Build
Wsparcie iOScargo-lipo + .aXcode + .a
BudowanieCargo (wbudowany)CMake / Ninja
Czas budowania2–5 min (clean)5–15 min (clean)
Ekosystemcrates.io (200k+ krat)vcpkg / Conan (100k+ bibliotek)

Rust jest bezpieczniejszy niż C++ i bardziej produktywny — kompilator łapie błędy, które w C++ ujawniłyby się w czasie wykonania. C++ ma bogatszy ekosystem bibliotek mobilnych. Dla nowych projektów Rust jest preferowany; istniejący kod C++ jest portowany stopniowo.

Często zadawane pytania

Czym Rust różni się od C++ w programowaniu mobilnym?

Główna różnica — bezpieczeństwo pamięci na etapie kompilacji. W Rust nie ma nullptr, zwisających wskaźników i wyścigów danych dzięki systemowi własności (ownership) i borrow checker. C++ polega na dyscyplinie programisty, Rust — na kontrolach kompilatora.

Czy można używać Rust w programowaniu Android?

Tak, przez Android NDK. Google oficjalnie wspiera Rust w AOSP (Android Open Source Project). Rust kompiluje się do bibliotek .so przez cargo-ndk. FFI (Foreign Function Interface) przez JNI działa tak samo jak dla C++.

Czym jest cargo i jak pomaga w programowaniu w Rust?

Cargo — menedżer pakietów i system budowania Rust. Pobiera zależności z crates.io, kompiluje projekt i uruchamia testy. W programowaniu mobilnym cargo-ndk rozszerza Cargo o cross-kompilację dla Android ABI.

Czy Rust nadaje się do iOS, czy tylko do Androida?

Rust obsługuje obie platformy. Dla iOS używany jest cargo-lipo do uniwersalnych binarek (arm64 + x86_64 symulator). Kod Rust kompiluje się do biblioteki statycznej .a i linkuje przez Xcode.

Czy warto uczyć się Rust do programowania mobilnego w 2026 roku?

Tak, Rust staje się standardem dla wieloplatformowych SDK i modułów natywnych. Google, Meta i Mozilla inwestują w Rust. Dla komponentów performance-critical Rust jest bezpieczniejszy i bardziej produktywny niż C++.

Podsumowanie

  • Rust — język systemowy z bezpieczeństwem pamięci bez GC dzięki ownership, borrowing i lifetimes
  • Borrow checker zapobiega wyścigom danych i zwisającym wskaźnikom na etapie kompilacji
  • Moduły natywne są budowane przez cargo-ndk (Android .so) i cargo-lipo (iOS .a)
  • UniFFI generuje wiązania FFI dla Kotlin i Swift — standard Mozilla dla mobilnych SDK
  • WebAssembly umożliwia uruchamianie Rust w mobilnych WebView z wydajnością near-native
  • Google używa Rust w AOSP — o 70% zmniejszono podatności pamięci w docelowych komponentach
  • Rust vs C++: Rust bezpieczniejszy, C++ z bogatszym ekosystemem; dla nowych modułów natywnych wybiera się Rust

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również