Scoped Storage — ce este, gestionarea fișierelor și accesul la stocare

Autor: IT Sectr Publicat: 2026-07-10 Timp de citire: 10 min

Scoped Storage — este un model de acces la sistemul de fișiere introdus în Android 10 (API 29) care limitează accesul arbitrar al aplicațiilor la stocarea partajată a dispozitivului. Conform Google Android Developer Documentation (2024), Scoped Storage înlocuiește vechiul model de permisiuni READ_EXTERNAL_STORAGE și WRITE_EXTERNAL_STORAGE, oferind aplicațiilor acces doar la propriile fișiere într-un sandbox izolat și la colecții comune prin MediaStore. Acest model sporește confidențialitatea datelor utilizatorilor și previne colectarea neautorizată de informații de către aplicații.

Puncte principale

  • Scoped Storage — model de acces la fișiere în Android 10+, care limitează citirea arbitrară a stocării partajate.
  • Aplicația are propriul sandbox cu acces complet fără permisiuni suplimentare.
  • Pentru accesul la fișiere comune (foto, video, audio) se utilizează MediaStore API.
  • Pentru accesul la directoare și fișiere arbitrare se utilizează Storage Access Framework (SAF).
  • Permisiunile READ_EXTERNAL_STORAGE și WRITE_EXTERNAL_STORAGE și-au pierdut valabilitatea în majoritatea scenariilor.

Ce este Scoped Storage în Android?

Scoped Storage — este o modificare arhitecturală în Android 10 (API 29) care schimbă fundamental modul de acces al aplicațiilor la sistemul de fișiere al dispozitivului. În loc de acces complet la stocarea partajată, aplicația primește acces doar la propriul sandbox și la anumite colecții de fișiere media prin MediaStore.

Înainte de Scoped Storage, orice aplicație cu permisiunea READ_EXTERNAL_STORAGE putea citi toate fișierele din stocarea partajată — fotografii, documente, descărcări, datele altor aplicații. Acest lucru crea riscuri de confidențialitate: aplicațiile necinstite puteau colecta informații despre utilizator fără știrea acestuia.

Conform Google I/O 2019, peste 65% dintre utilizatorii Android consideră confidențialitatea datelor un factor critic în alegerea unei aplicații. Scoped Storage este un răspuns direct la această cerință: fiecare aplicație funcționează într-un mediu izolat și obține acces la datele altora doar cu consimțământul explicit al utilizatorului.

Important: Scoped Storage în Android 10 a fost opțional (aplicația îl putea dezactiva prin requestLegacyExternalStorage). Începând cu Android 11 (API 30), Scoped Storage a devenit obligatoriu pentru toate aplicațiile, indiferent de target SDK.

De ce a fost necesar Scoped Storage

Google a introdus Scoped Storage pentru a rezolva trei probleme fundamentale ale vechiului model de acces la fișiere: confidențialitatea, gestionarea permisiunilor și curățarea fișierelor reziduale.

Problema confidențialității

În modelul vechi, o aplicație cu READ_EXTERNAL_STORAGE putea scana întreaga stocare partajată și colecta metadate despre fișierele utilizatorului — coordonatele geografice ale fotografiilor, numele documentelor, structura directoarelor. Scoped Storage elimină această posibilitate: chiar și având permisiunea, aplicația vede doar fișierele create de ea însăși și pe cele selectate explicit de utilizator prin SAF.

Problema curățării la dezinstalare

Înainte de Scoped Storage, aplicația putea lăsa fișiere în stocarea partajată după dezinstalare. În timp, se acumulau directoare gunoi. Scoped Storage rezolvă aceasta: toate fișierele din sandbox-ul aplicației sunt șterse odată cu aplicația, iar fișierele prin MediaStore au un proprietar și pot fi curățate de sistem.

AspectModel vechi (Legacy)Scoped Storage
Acces la stocarea partajatăComplet (cu permisiune)Doar propriul sandbox
Fișiere mediaCale directă de fișierPrin URI MediaStore
Fișiere altoraÎntotdeauna disponibileDoar prin SAF
Curățare la dezinstalareFișierele rămânSandbox-ul este șters
Controlul utilizatoruluiMinimConsimțământ explicit pentru fiecare fișier

Scoped Storage face parte din strategia generală Google de consolidare a confidențialității în Android, care include și permisiunile „doar în timpul utilizării”, indicatoarele de acces la cameră și microfon și Privacy Dashboard.

Directorul privat al aplicației

Fiecare aplicație în Android primește propriul director privat, accesibil prin Context.getFilesDir() și context.getCacheDir(). Pentru accesul la directorul privat extern (partajat) se utilizează Context.getExternalFilesDir().

În Scoped Storage, aplicația are acces complet la propriul director privat extern fără nicio permisiune. Acesta este locul principal pentru stocarea fișierelor care nu ar trebui să fie accesibile altor aplicații sau pe care aplicația le creează pentru propria utilizare.

kotlin
import android.os.Environment
import java.io.File
import java.io.IOException

class FileManager {

    fun saveToAppStorage(context: Context, fileName: String, data: ByteArray) {
        val appDir = context.getExternalFilesDir(null)
            ?: return
        val file = File(appDir, fileName)
        file.writeBytes(data)
    }

    fun readFromAppStorage(context: Context, fileName: String): ByteArray? {
        val appDir = context.getExternalFilesDir(null)
            ?: return null
        val file = File(appDir, fileName)
        return file.takeIf { it.exists() }?.readBytes()
    }
}

Calea către directorul privat extern: /storage/emulated/0/Android/data/{packageName}/files/. Începând cu Android 11, calea directă de fișier nu este disponibilă — doar prin API. Aceasta este o altă consolidare a securității Scoped Storage.

MediaStore — acces la fișiere media

MediaStore — este API-ul principal pentru accesul la fișierele media partajate (imagini, video, audio) în Scoped Storage. Aplicația nu lucrează cu căi de fișiere, ci cu content URIs furnizate de MediaStore provider.

MediaStore este împărțit în trei colecții principale: Images, Video și Audio. Fiecare colecție suportă operații CRUD prin ContentResolver. Pentru inserarea unui fișier nou în colecția Images se utilizează MediaStore.Images.Media, pentru interogarea celor existente — query cu URI-ul corespunzător.

kotlin
import android.content.ContentValues
import android.provider.MediaStore
import android.os.Environment
import java.io.OutputStream

fun saveImageToGallery(context: Context, bitmap: Bitmap, title: String) {
    val values = ContentValues().apply {
        put(MediaStore.Images.Media.DISPLAY_NAME, "$title.jpg")
        put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
        put(
            MediaStore.Images.Media.RELATIVE_PATH,
            "${Environment.DIRECTORY_PICTURES}/MyApp"
        )
    }

    val uri = context.contentResolver
        .insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
        ?: return

    context.contentResolver.openOutputStream(uri)?.use { output: OutputStream ->
        bitmap.compress(
            Bitmap.CompressFormat.JPEG,
            95,
            output
        )
    }
}

Important: MediaStore nu suportă căi de fișiere arbitrare — doar content URIs. Încercarea de a obține calea fișierului din URI prin MediaStore.Files.getContentUri() nu va da o cale directă către fișier pe Android 11+. În schimb, utilizează ContentResolver.openInputStream() și openOutputStream() pentru lucrul cu conținutul.

Storage Access Framework (SAF)

Storage Access Framework (SAF) — este API-ul pentru accesul la fișiere și directoare arbitrare în afara sandbox-ului aplicației. SAF oferă utilizatorului o interfață de selecție a fișierului sau directorului, după care aplicația primește un content URI cu acces temporar.

SAF este utilizat pentru scenarii care nu sunt acoperite de MediaStore: lucrul cu documente arbitrare (PDF, ZIP, APK), accesul la directoare de pe cardul SD, importul și exportul de fișiere din alte aplicații. Utilizatorul selectează explicit fișierul prin selectorul de fișiere al sistemului — aceasta garantează consimțământul său pentru acces.

kotlin
import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.provider.DocumentsContract

const val REQUEST_CODE_PICK_DIR = 1001

fun pickDirectory(activity: Activity) {
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
    activity.startActivityForResult(intent, REQUEST_CODE_PICK_DIR)
}

fun handlePickResult(requestCode: Int, data: Intent?) {
    if (requestCode == REQUEST_CODE_PICK_DIR && data != null) {
        val treeUri: Uri = data.data ?: return

        // Obține permisiunea persistentă URI
        val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
                       Intent.FLAG_GRANT_WRITE_URI_PERMISSION
        contentResolver.takePersistableUriPermission(treeUri, flags)
    }
}

SAF oferă aplicației acces la directorul selectat de utilizator până la repornirea dispozitivului (când se utilizează takePersistableUriPermission). Aceasta este singura modalitate de a obține acces la fișiere arbitrare în stocarea partajată pe Android 11+.

Migrarea aplicației la Scoped Storage

Migrarea aplicației Android existente la Scoped Storage necesită modificări în câteva domenii cheie. Google recomandă o abordare etapizată cu testare pe Android 11+.

Înlocuirea căilor de fișiere cu content URIs

Înlocuiește toate operațiile directe cu File în stocarea partajată cu ContentResolver.openInputStream / openOutputStream. Pentru fișierele din sandbox-ul aplicației (getExternalFilesDir), căile de fișiere continuă să funcționeze.

Actualizarea AndroidManifest

Elimină READ_EXTERNAL_STORAGE și WRITE_EXTERNAL_STORAGE dacă nu sunt necesare pentru scenarii specifice (de exemplu, gestionarea fișierelor — pentru aceasta există permisiunea specială MANAGE_EXTERNAL_STORAGE).

ScenariuAbordare vecheAbordare Scoped Storage
Salvarea unei fotografiiFile(path).writeBytes()MediaStore + ContentResolver
Citirea unui PDFFile(path).inputStream()SAF ACTION_OPEN_DOCUMENT
Fișiere propriiEnvironment.getExternalStorageDirectory()context.getExternalFilesDir()
CacheFile(cacheDir).writeBytes()context.cacheDir (fără schimbări)

După migrare, testează aplicația pe Android 11+ (API 30) cu targetSdk = 30 sau mai mare în build.gradle. Asigură-te că toate operațiile cu fișiere în stocarea partajată funcționează prin MediaStore sau SAF, nu prin căi directe de fișiere.

kotlin
import android.os.Build

fun isScopedStorage(): Boolean {
    return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
}

fun compatReadFile(context: Context, uri: Uri): ByteArray? {
    return if (isScopedStorage()) {
        context.contentResolver
            .openInputStream(uri)?.readBytes()
    } else {
        File(uri.path ?: return null)
            .takeIf { it.exists() }
            ?.readBytes()
    }
}

Conform Google Play Console (2024), peste 78% dintre dispozitivele Android active rulează pe Android 10+ cu Scoped Storage. Migrarea este un pas obligatoriu pentru publicarea actualizărilor în Google Play: aplicațiile noi trebuie să targeteze API 31+, actualizările — API 30+.

Întrebări frecvente

Pot dezactiva Scoped Storage în Android 11?

Nu, începând cu Android 11 (API 30), Scoped Storage este obligatoriu pentru toate aplicațiile. Flag-ul requestLegacyExternalStorage, disponibil în Android 10, nu funcționează pe API 30+. Singura modalitate de a obține acces larg la sistemul de fișiere este permisiunea MANAGE_EXTERNAL_STORAGE, dar aceasta este destinată doar managerilor de fișiere și antivirusurilor.

Ce este MANAGE_EXTERNAL_STORAGE și cum se obține?

MANAGE_EXTERNAL_STORAGE — o permisiune specială pentru aplicațiile care necesită acces complet la sistemul de fișiere (manageri de fișiere, instrumente de backup). Solicitarea permisiunii deschide un ecran de sistem cu o avertizare pentru utilizator. La publicarea în Google Play, este necesară completarea formularului Declaration despre necesitatea acestei permisiuni.

Cum obțin calea fișierului dintr-un content URI în Scoped Storage?

În Scoped Storage pe Android 11+, nu se poate obține o cale directă de fișier dintr-un content URI. În schimb, utilizează ContentResolver.openInputStream() pentru citire și openOutputStream() pentru scriere. Dacă ai nevoie de calea fișierului pentru compatibilitate cu o bibliotecă terță — creează o copie a fișierului în getCacheDir() și lucrează cu copia.

Cum afectează Scoped Storage FileProvider?

FileProvider continuă să funcționeze fără modificări — este utilizat pentru a oferi acces la fișierele din sandbox-ul aplicației altor aplicații prin content URIs. Scoped Storage nu afectează FileProvider, deoarece FileProvider funcționează la nivel de content URIs, nu de căi directe de fișiere.

Cum verific dacă dispozitivul suportă Scoped Storage?

Verifică Build.VERSION.SDK_INT: dacă >= Build.VERSION_CODES.Q (29), dispozitivul suportă Scoped Storage. Totuși, pe Android 10, Scoped Storage poate fi dezactivat prin requestLegacyExternalStorage. Pe Android 11+, verifică dacă flag-ul requestLegacyExternalStorage este setat în manifest — dacă nu, Scoped Storage este activ.

Rezumat

  • Scoped Storage — model de acces la fișiere în Android 10+, care limitează citirea arbitrară a stocării partajate.
  • Aplicația are acces complet la propriul sandbox privat fără permisiuni suplimentare.
  • Pentru accesul la fișierele media partajate se utilizează MediaStore API cu content URIs.
  • Pentru accesul la fișiere și directoare arbitrare se utilizează Storage Access Framework (SAF).
  • Începând cu Android 11, Scoped Storage este obligatoriu pentru toate aplicațiile.
  • Permisiunile READ_EXTERNAL_STORAGE și WRITE_EXTERNAL_STORAGE nu funcționează în majoritatea scenariilor pe Android 11+.
  • La migrare, înlocuiește căile directe de fișiere cu ContentResolver.openInputStream / openOutputStream.

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și