Portare un'app Tauri sul telefono: che cosa è supportato oggi
Hai un'app desktop in Tauri e ti chiedi se puoi portarla su Android e iOS senza riscriverla. La risposta breve, secondo la documentazione consultata il 2026-11-13, è che il supporto mobile fa parte di Tauri 2
dalla versione stabile del 2 ottobre 2024: non è più una promessa futura. Il core resta Rust, l'interfaccia resta una WebView, e i sottocomandi tauri android e tauri ios affiancano
tauri dev e tauri build nelle fasi di avvio e di compilazione. I limiti sono concreti: non tutti i plugin ufficiali funzionano su telefono, l'updater è solo desktop, per iOS serve un Mac e la costruzione automatica
con tauri-action è ancora marcata come sperimentale.
Una precisazione sul titolo e su ciò che ho provato. La documentazione non pubblica una roadmap con date, e questo articolo riporta lo stato attuale, non previsioni. Non ho costruito nessuna app mobile: sulla macchina di scrittura non ci sono Rust,
Android SDK né Xcode. Ho eseguito la sola configurazione di Vite mostrata più sotto, ho validato tauri.conf.json contro lo schema ufficiale e ho letto la documentazione, il riferimento della CLI e le guide di distribuzione. Gli altri
listati sono schemi da adattare. Prima di questo articolo conviene aver letto
la distribuzione su desktop, perché firme e store seguono la stessa logica.
Come funziona Tauri su mobile
L'architettura è la stessa del desktop: un core in Rust e un'interfaccia web. La WebView è quella del sistema: su Android la WebView di sistema, basata su Chromium, la cui versione dipende dal fornitore di WebView scelto sul dispositivo; su iOS, WebKit. Il codice Rust viene compilato come libreria e caricato dal progetto nativo: la guida di sviluppo spiega che Tauri aggiunge all'Xcode project una fase di build che esegue la CLI per compilare i sorgenti Rust. Per la parte nativa il progetto ha scelto Kotlin su Android e Swift su iOS, come scrive l'annuncio della versione 2.0.
// src-tauri/src/lib.rs
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
L'attributo cfg_attr(mobile, tauri::mobile_entry_point) è l'unica cosa che distingue un progetto pronto per il telefono: quando la compilazione ha come bersaglio Android o iOS (il cfg mobile),
run diventa il punto d'ingresso invocato dal progetto nativo; sul desktop l'attributo non fa nulla. Per questo il builder sta in una funzione pubblica run dentro lib.rs, che il progetto nativo può richiamare. Il resto, cioè
i comandi e i tipi che viaggiano fra Rust e interfaccia, funziona come nell'articolo sui
tipi condivisi.
Preparare l'ambiente
Gli strumenti sono pesanti e vanno installati una volta. La guida ai prerequisiti li separa per sistema.
# --- Android (Linux; su macOS e Windows cambiano i percorsi) ---
# 1. installa Android Studio, poi dal suo SDK Manager:
# Android SDK Platform, Platform-Tools, NDK (Side by side), Build-Tools, Command-line Tools
export JAVA_HOME=/opt/android-studio/jbr
export ANDROID_HOME="$HOME/Android/Sdk"
export NDK_HOME="$ANDROID_HOME/ndk/$(ls -1 $ANDROID_HOME/ndk)"
rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android
# --- iOS (solo macOS, con Xcode completo e non i soli Command Line Tools) ---
rustup target add aarch64-apple-ios x86_64-apple-ios aarch64-apple-ios-sim
brew install cocoapods
Per Android installi Android Studio e, dal suo SDK Manager, SDK Platform, Platform-Tools, NDK (Side by side), Build-Tools e Command-line Tools. JAVA_HOME punta al JDK incluso in Android Studio, ANDROID_HOME alla cartella dell'SDK
e NDK_HOME alla versione di NDK installata (l'espressione con ls prende l'unica cartella presente: se ne hai più di una, scegli tu). I quattro target Rust coprono le architetture dei dispositivi e degli emulatori.
Per iOS serve Xcode completo, non soltanto gli strumenti da riga di comando, più CocoaPods; lo sviluppo iOS è disponibile solo su macOS.
Il primo avvio sul simulatore e sul dispositivo
I comandi seguono la forma del desktop. init crea il progetto nativo, dev compila ed esegue con ricarica a caldo dell'interfaccia.
# Android: crea il progetto nativo, poi avvia su un dispositivo collegato o chiede quale emulatore usare
npm run tauri android init
npm run tauri android dev
# iOS (solo macOS): stesso schema, con il simulatore scelto per nome
npm run tauri ios init
npm run tauri ios dev 'iPhone 15'
# iOS su dispositivo fisico: la CLI propone l'indirizzo da usare per il server di sviluppo
npm run tauri ios dev -- --force-ip-prompt
Per impostazione predefinita dev prova a usare un dispositivo collegato e, se non lo trova, ti chiede quale simulatore avviare; passando il nome del dispositivo ('iPhone 15') scegli in anticipo. Se vuoi lavorare
con Android Studio o Xcode, aggiungi --open e lascia vivo il processo della CLI finché l'IDE è aperto. Per un iPhone fisico c'è un vincolo in più: il server di sviluppo non può ascoltare solo su localhost,
perché il telefono deve raggiungerlo in rete, e la CLI espone l'indirizzo da usare nella variabile TAURI_DEV_HOST.
import { defineConfig } from 'vite';
const host = process.env.TAURI_DEV_HOST;
export default defineConfig({
clearScreen: false,
server: {
host: host || false,
port: 1420,
strictPort: true,
hmr: host
? {
protocol: 'ws',
host,
port: 1421,
}
: undefined,
},
});
// Valore di `server` letto importando il file con Node 24 e Vite 8.3.8 (due esecuzioni identiche):
// senza TAURI_DEV_HOST: {"host":false,"port":1420,"strictPort":true}
// con TAURI_DEV_HOST=192.168.1.20: {"host":"192.168.1.20","port":1420,"strictPort":true,"hmr":{"protocol":"ws","host":"192.168.1.20","port":1421}}
È la configurazione proposta dalla guida. host: host || false lascia il server chiuso alla rete quando la variabile non c'è, e lo apre sull'indirizzo indicato quando c'è; hmr instrada anche il canale di ricarica a caldo sulla stessa
rete. Importandola due volte, con e senza variabile, il valore di server è quello mostrato nei commenti. Il progetto creato con create-tauri-app arriva già così; con un altro server di sviluppo, Angular compreso, vale lo stesso
principio (ascoltare sull'indirizzo di TAURI_DEV_HOST) da applicare con le opzioni di quel server. Per fare il debug serve l'ispettore: Safari su iOS, mentre su Android si apre chrome://inspect in Chrome.
Configurazione e permessi specifici del telefono
Alcune chiavi di tauri.conf.json esistono solo per il mobile, e le capability hanno un campo per scegliere la piattaforma.
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Appunti",
"version": "1.2.3",
"identifier": "dev.example.appunti",
"build": {
"devUrl": "http://localhost:1420",
"beforeDevCommand": "npm run dev",
"beforeBuildCommand": "npm run build",
"frontendDist": "../dist"
},
"bundle": {
"active": true,
"android": { "minSdkVersion": 24 },
"iOS": { "minimumSystemVersion": "15.0", "developmentTeam": "ABCDE12345" }
}
}
bundle.android.minSdkVersion è il livello minimo di API Android: se il telefono ha un livello inferiore il sistema impedisce l'installazione, e il valore predefinito è 24. bundle.iOS.minimumSystemVersion vale
"15.0" se non lo scrivi. developmentTeam è obbligatorio per lo sviluppo iOS perché la firma è imposta, e si può sovrascrivere con la variabile APPLE_DEVELOPMENT_TEAM. Per Google Play il numero di versione
(versionCode) è ricavato dalla versione dell'app con la formula maggiore per un milione più minore per mille più patch: con 1.2.3 diventa 1002003. Puoi sostituirlo in bundle.android.versionCode se vuoi codici sequenziali.
Il file è valido contro lo schema 2.12.5.
{
"$schema": "../gen/schemas/mobile-schema.json",
"identifier": "mobile-capability",
"description": "Permessi disponibili solo su telefono",
"windows": ["main"],
"platforms": ["iOS", "android"],
"permissions": [
"biometric:allow-authenticate",
"barcode-scanner:allow-scan"
]
}
Il campo platforms limita la capability ai bersagli indicati; senza di esso vale per tutti. È il modo previsto per abilitare permessi di plugin che esistono solo sul telefono, come la biometria o la lettura di codici a barre: su desktop
quei plugin non sono disponibili. È la divisione che usa la guida delle capability stessa, con un file per il desktop e uno per il mobile.
Che cosa copre il catalogo dei plugin sul telefono
È il punto che decide la fattibilità. Dalla tabella ufficiale dei plugin (README del repository, letta il 2026-11-13) ricavo questa corrispondenza fra bisogno e plugin; la classificazione completa è nell' articolo sui plugin.
| Bisogno | Plugin ufficiale | Piattaforme dichiarate |
|---|---|---|
| Leggere codici a barre e QR con la fotocamera | barcode-scanner | solo iOS e Android |
| Autenticazione biometrica | biometric | solo iOS e Android |
| Posizione del dispositivo | geolocation | solo iOS e Android |
| Vibrazione e feedback aptico | haptics | solo iOS e Android |
| Lettura e scrittura di tag NFC | nfc | solo iOS e Android |
| Torcia | torch | solo iOS e Android |
| Notifiche, dialoghi, appunti, apertura di link e file | notification, dialog, clipboard-manager, opener | desktop e mobile |
| Dati locali | store, sql | desktop e mobile |
| File system | fs | mobile non dichiarato |
| Aggiornamento dentro l'app | updater | solo desktop |
| Scattare una foto | nessuno nella tabella | - |
La tabella dice due cose. Primo, per le funzioni da telefono più comuni (biometria, posizione, NFC, codici a barre) esiste un plugin ufficiale; secondo, mancano a catalogo funzioni che si danno per scontate, come scattare una foto, e il file system sul mobile non è dichiarato. Dove manca un plugin hai tre strade: usare un plugin della comunità dopo i controlli visti nell'articolo sui plugin, scrivere un plugin nativo tuo, oppure rinunciare alla funzione.
Quando serve codice nativo: un plugin in Kotlin
Un plugin può includere una libreria Android in Kotlin (o Java) e un pacchetto Swift per iOS. Il modello è quello del desktop: il frontend chiama un comando, la parte Rust del plugin lo inoltra al codice nativo e restituisce il risultato.
// android/src/main/java/ExamplePlugin.kt (importazioni omesse, come nella guida)
@TauriPlugin
class ExamplePlugin(private val activity: Activity): Plugin(activity) {
@Command
fun openCamera(invoke: Invoke) {
val ret = JSObject()
ret.put("path", "/path/to/photo.jpg")
invoke.resolve(ret)
}
}
La classe estende Plugin ed è annotata con @TauriPlugin; ogni metodo annotato con @Command può essere chiamato da Rust o da JavaScript. Il metodo riceve un oggetto Invoke e risponde con
invoke.resolve. Il percorso /path/to/photo.jpg è un segnaposto della guida, non un'implementazione: la fotocamera vera va scritta. Per iOS la guida prevede una classe Swift con funzioni @objc che prendono un
parametro Invoke. Il modello di permessi resta quello delle capability, e i progetti si creano con la CLI di plugin (plugin android init e plugin ios init) o con le opzioni --android e --ios alla creazione.
Distribuzione: Google Play e App Store
Il pacchetto per Google Play è l'Android App Bundle (AAB); l'APK serve per prove o per distribuire fuori dallo store. Per iOS la build produce un file IPA per App Store Connect, che poi si carica con Apple.
# Android: pacchetto per Google Play (AAB) e APK per prove o distribuzione fuori dallo store
npm run tauri android build -- --aab
npm run tauri android build -- --apk --target aarch64
# iOS (solo macOS): pacchetto IPA per App Store Connect, poi caricamento con altool
npm run tauri ios build -- --export-method app-store-connect
xcrun altool --upload-app --type ios \
--file "src-tauri/gen/apple/build/arm64/Appunti.ipa" \
--apiKey "$APPLE_API_KEY_ID" --apiIssuer "$APPLE_API_ISSUER"
Senza --target, Tauri costruisce per tutte le architetture Android supportate (aarch64, armv7, i686, x86_64); indicarne una sola accorcia la build e produce un pacchetto utile per un test su un dispositivo noto. Su iOS il valore
app-store-connect di --export-method prepara l'IPA per l'App Store, mentre release-testing la prepara per TestFlight. La guida usa altool con una chiave API di App Store Connect per il caricamento: è lo stesso nome del vecchio
strumento di notarizzazione, ma qui indica il caricamento nello store, ed è l'uso previsto dalla documentazione di Tauri. Servono l'iscrizione ai rispettivi programmi sviluppatori, la firma del codice e l'app registrata sullo store; per iOS l'identificativo
dell'app registrata deve coincidere con identifier in tauri.conf.json.
In integrazione continua, tauri-action ha un input mobile che la sua documentazione definisce sperimentale: sostituisce il comando di build con quello Android o iOS, ma non carica l'app sugli store e non installa Xcode o gli SDK al posto tuo.
L'annuncio della 2.0 del 2024 diceva che l'azione non supportava ancora il mobile: lo stato di oggi è quindi cambiato, con la cautela del termine «experimental». L'updater non è disponibile su telefono, quindi gli aggiornamenti passano dagli store.
Quando conviene e quando no
Questi sono i criteri che pesano, senza una gerarchia:
- Hai già un core Rust e un'interfaccia web che vuoi riutilizzare su desktop e telefono.
- Le funzioni native che servono hanno un plugin nella tabella, o sei pronto a scrivere Kotlin e Swift.
- Accetti la WebView di sistema come motore di rendering, con le differenze che comporta fra dispositivi.
- Non hai bisogno dell'aggiornamento in app, perché sul telefono passa dagli store.
- Hai un Mac se la destinazione include iOS.
Se uno dei punti salta, il resto non compensa: un'app che dipende dalla fotocamera o da API native non coperte ti obbliga a scrivere il codice nativo che speravi di evitare, e senza un Mac iOS resta fuori. Non ho confrontato Tauri con Flutter o React Native per dimensioni o prestazioni, perché non ho misure mie e non ne cito di altrui; il confronto che serve è quello su un prototipo della tua app, sullo stesso dispositivo.
Sul futuro: nella documentazione che ho letto non c'è una roadmap con date. L'annuncio del 2024 indicava come priorità l'esperienza di sviluppo mobile, e sul registro dei crate la serie 3 di tauri è in alpha (3.0.0-alpha.6, pubblicata il 2026-11-06): sono fatti, non promesse.
Domande frequenti
Tauri mobile è stabile?
Il supporto mobile fa parte della versione 2.0 stabile del 2 ottobre 2024. Parti singole sono più giovani: l'input mobile di tauri-action è sperimentale, e diversi plugin dichiarano il mobile come non provato. Valuta la stabilità funzione per funzione sul tuo prototipo.
Posso sviluppare per iOS da Linux o Windows?
No. La documentazione dei prerequisiti dice che lo sviluppo iOS richiede Xcode ed è disponibile solo su macOS. Android invece si sviluppa su tutti e tre i sistemi.
Quali versioni minime di Android e iOS supporta?
I valori predefiniti del riferimento di configurazione sono API 24 per Android (minSdkVersion) e iOS 15.0 (minimumSystemVersion); puoi cambiarli in tauri.conf.json.
Riuso il codice Rust del desktop senza modifiche?
La logica sì, purché non dipenda da plugin o API solo desktop. Dove serve un comportamento diverso usi cfg nel Rust e capability con platforms nella configurazione. La distribuzione, invece, è un lavoro a parte per ciascuno store.
Che cosa sai fare adesso
Sai che Tauri 2 include Android e iOS, come si prepara l'ambiente e come si avviano progetto e simulatore, quali chiavi di configurazione e di capability sono specifiche del telefono, e che cosa copre il catalogo dei plugin. Sai che i pacchetti per gli store si producono con
tauri android build --aab e tauri ios build --export-method app-store-connect, e che aggiornamenti e CI hanno limiti dichiarati. Il passo successivo non è teorico: costruisci un prototipo con la funzione più rischiosa della tua app e misura lì ciò che qui ho solo letto.
Fonti
- Tauri 2.0 Stable Release - data del rilascio stabile, supporto mobile con Swift e Kotlin, plugin non tutti compatibili, stato di tauri-action nel 2024, consultata il 2026-11-13
- Tauri 2: Prerequisites - Android Studio, variabili d'ambiente, target Rust Android e iOS, Xcode solo su macOS, consultata il 2026-11-13
- Tauri 2: Develop - tauri android dev e tauri ios dev, TAURI_DEV_HOST, configurazione di Vite, ispettori web, consultata il 2026-11-13
- Tauri 2: Google Play - AAB, APK, versionCode derivato dalla versione, architetture, consultata il 2026-11-13
- Tauri 2: App Store - build iOS con export-method, IPA, altool e chiave API, identificativo dell'app, consultata il 2026-11-13
- Tauri 2: Mobile Plugin Development - plugin in Kotlin e Swift, annotazioni e comandi, consultata il 2026-11-13
- Tauri 2: Capabilities - campo platforms e capability per desktop e mobile, consultata il 2026-11-13
- Tauri 2: Configuration Reference - valori predefiniti di minSdkVersion e minimumSystemVersion, developmentTeam, consultata il 2026-11-13
- Tauri 2: Webview Versions - WebView di sistema su Android e WebKit su iOS, consultata il 2026-11-13
- tauri-apps/plugins-workspace: README al commit 9aa4f71 - tabella delle piattaforme per plugin e legenda, letto il 2026-11-13
- tauri-apps/tauri-action: README - input mobile dichiarato sperimentale, limiti dell'azione, letto il 2026-11-13
- crates.io: tauri - versione 3.0.0-alpha.6 e data di pubblicazione, letta dall'API del registro il 2026-11-13
La configurazione di Vite è stata importata ed eseguita con Node 24.11 e Vite 8.3.8 (due esecuzioni identiche) e controllata con tsc; tauri.conf.json è stato validato contro lo schema di Tauri 2.12.5 e i file di capability sono stati letti come JSON. Tutto il resto è uno schema da adattare, non compilato né eseguito: nessuna app mobile è stata costruita, perché sulla macchina di scrittura non ci sono Rust, Android SDK né Xcode.

Commenti
Caricamento commenti...
Accedi per commentare