La memoria interna dell'app è uno spazio dedicato sul dispositivo accessibile solo a un'applicazione specifica tramite archiviazione isolata. Secondo Android Developers, 2026, ogni applicazione riceve la propria directory sandbox a cui altre applicazioni non hanno accesso diretto. Questo approccio protegge i dati da letture non autorizzate e garantisce un funzionamento stabile in un ambiente multitasking di dispositivi mobili.
Punti chiave
Context.getFilesDir(), getCacheDir() e getDataDir() per accedere alla memoria internaNSDocumentDirectory e NSCachesDirectory nel contenitore Sandbox dell'appLa memoria interna dell'app è una directory isolata che il sistema operativo assegna a ciascuna applicazione durante l'installazione. Altre applicazioni e l'utente non possono accedere a questa directory tramite i gestori di file standard. Il sistema garantisce che tutti i dati all'interno di questa directory vengano completamente eliminati quando l'applicazione viene disinstallata. Questo approccio costituisce la base del modello di sicurezza dei sistemi operativi mobili, prevenendo la fuga di informazioni riservate tra programmi.
A differenza della memoria esterna (scheda SD), la memoria interna è sempre disponibile e non richiede la verifica della presenza del supporto. Le velocità di lettura e scrittura nella memoria flash NAND dei dispositivi moderni raggiungono 800–900 MB/s in lettura sequenziale e 200–300 MB/s in scrittura sequenziale, paragonabili agli SSD SATA. La dimensione dell'area allocata dipende dalla capacità totale del dispositivo e dalla politica del produttore: su dispositivi con 64 GB di memoria flash, l'app riceve da 16 a 64 MB di spazio iniziale con possibilità di espansione secondo necessità.
L'architettura della memoria interna differisce tra Android e iOS. Su Android, ogni applicazione riceve una directory /data/data/<package_name>/, all'interno della quale il sistema crea le sottodirectory files/, cache/ e databases/. Su iOS, l'applicazione funziona in un contenitore Sandbox con le directory Documents/, Library/ e tmp/, ciascuna con il proprio scopo e la propria politica di backup.
Gli sviluppatori hanno accesso a diversi metodi per salvare i dati nella memoria interna dell'app. Ogni metodo risolve un compito specifico ed è adatto a un particolare tipo di dato. La scelta del metodo corretto influisce direttamente sulle prestazioni dell'applicazione, sulla facilità di sviluppo e sulla sicurezza dei dati dell'utente.
Il metodo di livello più basso è la scrittura diretta di file nella directory dei file. Un'app può creare qualsiasi file e directory all'interno della sua sandbox. Questo metodo è adatto per archiviare file multimediali, documenti dell'utente e qualsiasi dato binario che non richieda un'organizzazione strutturata. Su Android, l'accesso alla directory avviene tramite la chiamata Context.getFilesDir(), che restituisce il percorso assoluto alla directory dei file dell'app. Su iOS, la funzione NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) svolge uno scopo simile.
Per memorizzare coppie chiave-valore, Android offre SharedPreferences e il più moderno DataStore basato sulle coroutine Kotlin e sul protocollo protobuf. SharedPreferences memorizza i dati in un file XML all'interno della directory /data/data/<package>/shared_prefs/. Nonostante la semplicità d'uso, SharedPreferences presenta degli svantaggi: la scrittura sincrona può causare ritardi nel thread UI e la mancanza di type safety aumenta il rischio di errori. DataStore risolve questi problemi fornendo un'API asincrona basata su Flow e il pieno supporto dei tipi tramite schemi protobuf.
Per dati strutturati con connessioni relazionali, la scelta ottimale è SQLite o il wrapper Room. Il database è archiviato in un singolo file all'interno della directory databases/ e supporta la sintassi SQL completa. Room è una libreria ufficiale Jetpack che fornisce un'API type-safe, migrazione automatica dello schema e supporto per le coroutine. La dimensione del database può raggiungere diversi gigabyte senza una significativa perdita di prestazioni con una corretta indicizzazione. SQLite sui dispositivi mobili gestisce fino a 50.000 operazioni di scrittura al secondo su un processore flagship moderno.
Per memorizzare dati riservati come token di autenticazione e chiavi di crittografia, Android fornisce EncryptedSharedPreferences. Questo wrapper su SharedPreferences standard crittografa automaticamente chiavi e valori utilizzando AES256-GCM-None. La crittografia viene eseguita a livello di file prima della scrittura su disco, quindi anche con accesso fisico al dispositivo, un utente malintenzionato non può leggere il contenuto. EncryptedSharedPreferences fa parte della libreria AndroidX Security, che include anche EncryptedFile per crittografare interi file.
L'Android SDK fornisce un insieme di metodi per lavorare con la memoria interna tramite la classe Context. Ogni metodo restituisce un percorso a una directory di sistema specifica all'interno della sandbox dell'app. Esaminiamo le operazioni di base di scrittura e lettura dei file utilizzando Kotlin come esempio.
Il metodo principale per ottenere il percorso della directory dei file interna è context.filesDir. Restituisce un oggetto File che punta alla directory /data/data/<package>/files/. Al primo accesso, il sistema crea automaticamente tutte le directory padre necessarie. La dimensione dei file nella memoria interna non è esplicitamente limitata, ma il volume totale dei dati non deve superare lo spazio disponibile sulla partizione /data, che di solito costituisce il 60–80% della capacità totale della memoria flash.
val context = getApplicationContext()
val file = File(context.filesDir, "notes.txt")
file.writeText("Contenuto della nota")
val content = file.readText()
println("Letto: $content")
I metodi writeText e readText sono funzioni di estensione della libreria standard di Kotlin. Gestiscono automaticamente l'apertura e la chiusura degli stream, prevenendo perdite di memoria. Per i dati binari, utilizza writeBytes e readBytes, che non richiedono codifica e funzionano con array ByteArray. Quando si lavora con file di grandi dimensioni, si consiglia di utilizzare stream bufferizzati: BufferedReader e BufferedWriter per il testo, BufferedInputStream e BufferedOutputStream per i dati binari.
Per organizzare i file in una gerarchia, crea sottodirectory all'interno di filesDir. Questo aiuta a strutturare i dati per tipo: immagini, documenti, file di esportazione. Il metodo mkdirs() crea tutte le directory mancanti nel percorso, incluse quelle nidificate. Assicurati che l'operazione di creazione sia riuscita — il metodo restituisce true solo quando vengono create nuove directory. Gli errori di creazione sono spesso correlati a spazio insufficiente sulla partizione /data o all'esaurimento degli inode del file system.
val imagesDir = File(context.filesDir, "images")
if (imagesDir.mkdirs()) {
println("Directory creata")
}
val imageFile = File(imagesDir, "photo.jpg")
imageFile.writeBytes(byteArray)
Per verificare lo spazio disponibile prima di scrivere file di grandi dimensioni, utilizza File.getFreeSpace() o File.getUsableSpace(). Il secondo metodo restituisce il numero di byte disponibili per l'applicazione corrente considerando le quote di sicurezza — è più preciso nel contesto di dispositivi multi-utente. Se lo spazio disponibile è inferiore alla dimensione prevista del file, mostra un messaggio all'utente e suggerisci di liberare spazio nelle impostazioni del dispositivo.
Su iOS, ogni applicazione funziona in un contenitore Sandbox isolato. Il sistema non fornisce un'API per uscire dai suoi limiti senza entitlements speciali. Lo strumento principale per lavorare con il file system è la classe FileManager del framework Foundation. Il contenitore Sandbox include diverse directory standard, ciascuna con la propria politica di backup.
La directory Documents è destinata ai dati dell'utente che devono persistere tra gli avvii dell'applicazione ed essere ripristinati dal backup. iOS include automaticamente questa directory nei backup di iCloud e iTunes. Il metodo urls(for:in:) restituisce un array di URL della directory richiesta — il primo elemento dell'array è quello principale.
let fm = FileManager.default
let docs = fm.urls(
for: .documentDirectory,
in: .userDomainMask
).first!
let fileURL = docs.appendingPathComponent("data.plist")
try data.write(to: fileURL)
FileManager supporta un set completo di operazioni sui file: creazione, copia, spostamento, eliminazione e rinomina dei file. Ogni operazione può generare un errore, quindi tutte le chiamate devono essere racchiuse in un costrutto do-catch. Presta particolare attenzione all'eliminazione dei file — l'operazione è irreversibile e il ripristino dei dati dopo removeItem(at:) è impossibile senza un backup preliminare.
Non tutti i dati nel contenitore Sandbox devono essere inclusi nel backup di iCloud. Ad esempio, le immagini scaricate in cache o i file temporanei di elaborazione non necessitano di essere ripristinati — verranno ricreati al successivo utilizzo. Per escludere una directory o un file dal backup, imposta l'attributo isExcludedFromBackup su true. Apple raccomanda di escludere sempre dal backup i dati che possono essere ripristinati da remoto, per minimizzare l'utilizzo dello spazio di archiviazione iCloud e ridurre i tempi di ripristino.
var cacheURL = fm.urls(
for: .cachesDirectory,
in: .userDomainMask
).first!
cacheURL.hasExcludedFromBackupKey = true
var values = URLResourceValues()
values.isExcludedFromBackup = true
try cacheURL.setResourceValues(values)
Ogni tipo di memoria su un dispositivo mobile ha il suo scopo e le sue regole di utilizzo. Comprendere queste differenze aiuta lo sviluppatore a scegliere la posizione corretta per ogni tipo di dato. Di seguito è riportato un confronto dei tre principali tipi di memoria disponibili per un'applicazione.
| Caratteristica | Internal Storage | Directory Cache | External Storage |
|---|---|---|---|
| Visibilità per altre app | Nascosta | Nascosta | Accessibile |
| Cancellazione alla disinstallazione | Completa | Completa | Dipende dalla posizione |
| Backup | Android — no, iOS — sì (Documents) | No | Solo durante la sincronizzazione |
| Disponibilità senza supporto | Sempre | Sempre | Richiede scheda SD |
| Rischio di perdita dati | Minimo | Alto | Medio |
| Dimensione file consigliata | Fino a 100 MB | Fino a 50 MB | Qualsiasi |
La memoria interna è ottimale per memorizzare configurazioni dell'app, file di database e documenti dell'utente che non dovrebbero essere accessibili ad altri programmi. La directory cache è destinata a file temporanei che possono essere ricreati al successivo utilizzo: immagini scaricate, risposte API, dati intermedi di elaborazione. La memoria esterna è più adatta per file multimediali di grandi dimensioni (foto, video, musica) e dati che l'utente desidera condividere con altre applicazioni tramite accesso condiviso.
La scelta del tipo di memoria influisce anche sulla valutazione dell'app su Google Play e App Store. Le applicazioni che memorizzano grandi volumi di dati nella memoria interna senza pulizia ricevono recensioni negative: gli utenti si lamentano della mancanza di spazio. Secondo uno studio di App Annie, il 62% degli utenti elimina un'app se occupa più di 500 MB di memoria interna del dispositivo senza opzione di pulizia.
Una gestione corretta della memoria interna dell'app migliora le prestazioni, la sicurezza e l'esperienza utente. Le seguenti raccomandazioni si basano sulla documentazione ufficiale di Android e iOS, nonché sull'esperienza pratica nello sviluppo di applicazioni con milioni di installazioni.
Particolare attenzione dovrebbe essere dedicata al test dei casi limite. Verifica il comportamento dell'applicazione quando la memoria interna è piena, quando un'operazione di scrittura viene interrotta inaspettatamente (crash dell'app, chiamata in arrivo) e durante il ripristino da un backup iOS. In ciascuno di questi scenari, i dati devono rimanere coerenti o essere ripristinati all'ultimo stato stabile. Utilizza file transazionali: scrivi i dati in un file temporaneo, quindi rinominalo atomicamente nella destinazione. Questo impedisce la lettura di dati danneggiati in caso di errore di scrittura.
Non dimenticare il controllo dell'utente. Fornisci nelle impostazioni dell'app un'opzione per cancellare i dati temporanei e visualizzare il volume occupato della memoria interna. Secondo Google Play Console, le app con questa funzionalità ricevono il 18% in più di recensioni positive nella categoria «Prestazioni».
Domande frequenti
Tutti i dati dalla memoria interna dell'app vengono completamente eliminati. Il sistema operativo garantisce l'assenza di file residui, inclusi database, impostazioni e file temporanei. I dati sulla memoria esterna possono persistere.
Senza accesso root al dispositivo, altre app non possono leggere file da Internal Storage di un'altra app. Su Android, ciò richiede privilegi di superutente, mentre su iOS l'isolamento è applicato a livello di kernel tramite Sandbox.
Non esiste un limite esplicito, ma il volume totale è vincolato dallo spazio disponibile sulla partizione /data. Si consiglia di non superare 100 MB per applicazione — i volumi più grandi dovrebbero essere collocati su memoria esterna o nel cloud.
filesDir è destinato ai dati permanenti dell'app e il sistema non lo elimina se non necessario. cacheDir è per file temporanei che il sistema può eliminare in caso di memoria insufficiente. Il sistema non garantisce la persistenza di cacheDir.
La copia diretta da Internal Storage a una scheda SD è vietata dalla politica di sicurezza. Utilizza l'API MediaStore su Android 10+ o SAF (Storage Access Framework) per creare copie dei dati nella memoria condivisa con il consenso dell'utente.
Riepilogo
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.
Leggi anche