Scoped Storage — co to je, správa souborů a přístup k úložišti

Autor: IT Sectr Publikováno: 2026-07-10 Doba čtení: 10 min

Scoped Storage — je model přístupu k souborovému systému zavedený v Android 10 (API 29), který omezuje svévolný přístup aplikací ke sdílenému úložišti zařízení. Podle Google Android Developer Documentation (2024) Scoped Storage nahrazuje starý model oprávnění READ_EXTERNAL_STORAGE a WRITE_EXTERNAL_STORAGE a poskytuje aplikacím přístup pouze k jejich vlastním souborům v izolovaném sandboxu a ke sdíleným kolekcím prostřednictvím MediaStore. Tento model zvyšuje soukromí uživatelských dat a zabraňuje neoprávněnému shromažďování informací aplikacemi.

Hlavní body

  • Scoped Storage — model přístupu k souborům v Android 10+, který omezuje svévolné čtení sdíleného úložiště.
  • Aplikace má vlastní sandbox s plným přístupem bez dalších oprávnění.
  • Pro přístup ke sdíleným souborům (foto, video, audio) se používá MediaStore API.
  • Pro přístup k libovolným adresářům a souborům se používá Storage Access Framework (SAF).
  • Oprávnění READ_EXTERNAL_STORAGE a WRITE_EXTERNAL_STORAGE ztratila platnost pro většinu scénářů.

Co je Scoped Storage v Androidu?

Scoped Storage — je architektonická změna v Android 10 (API 29), která zásadně mění způsob přístupu aplikací k souborovému systému zařízení. Místo plného přístupu ke sdílenému úložišti aplikace získává přístup pouze ke svému sandboxu a k určitým kolekcím mediálních souborů prostřednictvím MediaStore.

Před Scoped Storage mohla jakákoli aplikace s oprávněním READ_EXTERNAL_STORAGE číst všechny soubory ve sdíleném úložišti — fotografie, dokumenty, stažené soubory, data jiných aplikací. To vytvářelo rizika pro soukromí: nepoctivé aplikace mohly shromažďovat informace o uživateli bez jeho vědomí.

Podle Google I/O 2019 považuje více než 65% uživatelů Androidu soukromí dat za kritický faktor při výběru aplikace. Scoped Storage je přímou odpovědí na tento požadavek: každá aplikace pracuje v izolovaném prostředí a získává přístup k datům ostatních pouze s výslovným souhlasem uživatele.

Důležité: Scoped Storage v Android 10 byl volitelný (aplikace jej mohla deaktivovat pomocí requestLegacyExternalStorage). Počínaje Android 11 (API 30) se Scoped Storage stal povinným pro všechny aplikace bez ohledu na target SDK.

Proč byl Scoped Storage potřeba

Google zavedl Scoped Storage k vyřešení tří zásadních problémů starého modelu přístupu k souborům: soukromí, správa oprávnění a čištění zbytkových souborů.

Problém soukromí

Ve starém modelu mohla aplikace s READ_EXTERNAL_STORAGE skenovat celé sdílené úložiště a shromažďovat metadata o souborech uživatele — zeměpisné souřadnice fotografií, názvy dokumentů, strukturu adresářů. Scoped Storage tuto možnost odstraňuje: i s oprávněním aplikace vidí pouze soubory, které sama vytvořila, a soubory výslovně vybrané uživatelem prostřednictvím SAF.

Problém čištění při odinstalaci aplikace

Před Scoped Storage mohla aplikace po odinstalaci zanechat soubory ve sdíleném úložišti. Postupem času se hromadily odpadkové adresáře. Scoped Storage to řeší: všechny soubory v sandboxu aplikace jsou smazány spolu s aplikací a soubory prostřednictvím MediaStore mají vlastníka a mohou být systémem vyčištěny.

AspektStarý model (Legacy)Scoped Storage
Přístup ke sdílenému úložištiPlný (s oprávněním)Pouze vlastní sandbox
Mediální souboryPřímá cesta k souboruPřes URI MediaStore
Cizí souboryVždy dostupnéPouze přes SAF
Čištění při odinstalaciSoubory zůstávajíSandbox je smazán
Kontrola uživateleMinimálníVýslovný souhlas pro každý soubor

Scoped Storage je součástí celkové strategie Google pro posílení soukromí v Androidu, která také zahrnuje oprávnění “pouze během používání”, indikátory přístupu ke kameře a mikrofonu a Privacy Dashboard.

Soukromý adresář aplikace

Každá aplikace v Androidu získává vlastní soukromý adresář přístupný prostřednictvím Context.getFilesDir() a context.getCacheDir(). Pro přístup k externímu (sdílenému) soukromému adresáři se používá Context.getExternalFilesDir().

V Scoped Storage má aplikace plný přístup ke svému externímu soukromému adresáři bez jakýchkoli oprávnění. Toto je hlavní místo pro ukládání souborů, které by neměly být přístupné jiným aplikacím nebo které aplikace vytváří pro vlastní potřebu.

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()
    }
}

Cesta k externímu soukromému adresáři: /storage/emulated/0/Android/data/{packageName}/files/. Počínaje Android 11 není přímá cesta k souboru dostupná — pouze přes API. Toto je další posílení bezpečnosti Scoped Storage.

MediaStore — přístup k mediálním souborům

MediaStore — je hlavní API pro přístup ke sdíleným mediálním souborům (obrázky, video, audio) v Scoped Storage. Aplikace nepracuje s cestami k souborům, ale s content URIs poskytovanými poskytovatelem MediaStore.

MediaStore je rozdělen do tří hlavních kolekcí: Images, Video a Audio. Každá kolekce podporuje CRUD operace prostřednictvím ContentResolver. Pro vložení nového souboru do kolekce Images se používá MediaStore.Images.Media, pro dotazování existujících — query s příslušným URI.

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
        )
    }
}

Důležité: MediaStore nepodporuje libovolné cesty k souborům — pouze content URIs. Pokus o získání cesty k souboru z URI prostřednictvím MediaStore.Files.getContentUri() neposkytne přímou cestu k souboru na Android 11+. Místo toho použijte ContentResolver.openInputStream() a openOutputStream() pro práci s obsahem.

Storage Access Framework (SAF)

Storage Access Framework (SAF) — je API pro přístup k libovolným souborům a adresářům mimo sandbox aplikace. SAF poskytuje uživateli rozhraní pro výběr souboru nebo adresáře, po kterém aplikace obdrží content URI s dočasným přístupem.

SAF se používá pro scénáře, které nejsou pokryty MediaStore: práce s libovolnými dokumenty (PDF, ZIP, APK), přístup k adresářům na SD kartě, import a export souborů z jiných aplikací. Uživatel explicitně vybírá soubor prostřednictvím systémového výběru souborů — to zaručuje jeho souhlas s přístupem.

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

        // Získat trvalé oprávnění URI
        val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
                       Intent.FLAG_GRANT_WRITE_URI_PERMISSION
        contentResolver.takePersistableUriPermission(treeUri, flags)
    }
}

SAF poskytuje aplikaci přístup k adresáři vybranému uživatelem až do restartu zařízení (při použití takePersistableUriPermission). Toto je jediný způsob, jak získat přístup k libovolným souborům ve sdíleném úložišti na Android 11+.

Migrace aplikace na Scoped Storage

Migrace existující Android aplikace na Scoped Storage vyžaduje změny v několika klíčových oblastech. Google doporučuje fázový přístup s testováním na Android 11+.

Nahrazení cest k souborům content URIs

Nahraďte všechny přímé operace File ve sdíleném úložišti pomocí ContentResolver.openInputStream / openOutputStream. Pro soubory v sandboxu aplikace (getExternalFilesDir) cesty k souborům nadále fungují.

Aktualizace AndroidManifest

Odstraňte READ_EXTERNAL_STORAGE a WRITE_EXTERNAL_STORAGE, pokud nejsou potřebné pro specifické scénáře (např. správa souborů — k tomu existuje zvláštní oprávnění MANAGE_EXTERNAL_STORAGE).

ScénářStarý přístupScoped Storage přístup
Uložení fotografieFile(path).writeBytes()MediaStore + ContentResolver
Čtení PDFFile(path).inputStream()SAF ACTION_OPEN_DOCUMENT
Vlastní souboryEnvironment.getExternalStorageDirectory()context.getExternalFilesDir()
MezipaměťFile(cacheDir).writeBytes()context.cacheDir (beze změny)

Po migraci otestujte aplikaci na Android 11+ (API 30) s targetSdk = 30 nebo vyšším v build.gradle. Ujistěte se, že všechny operace se soubory ve sdíleném úložišti fungují přes MediaStore nebo SAF, ne přes přímé cesty k souborům.

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()
    }
}

Podle Google Play Console (2024) více než 78% aktivních Android zařízení běží na Android 10+ s Scoped Storage. Migrace je povinným krokem pro publikování aktualizací v Google Play: nové aplikace musí cílit API 31+, aktualizace — API 30+.

Často kladené otázky

Lze vypnout Scoped Storage v Android 11?

Ne, počínaje Android 11 (API 30) je Scoped Storage povinný pro všechny aplikace. Příznak requestLegacyExternalStorage, dostupný v Android 10, nefunguje na API 30+. Jediný způsob, jak získat široký přístup k souborovému systému, je oprávnění MANAGE_EXTERNAL_STORAGE, ale je určeno pouze pro správce souborů a antiviry.

Co je MANAGE_EXTERNAL_STORAGE a jak jej získat?

MANAGE_EXTERNAL_STORAGE — zvláštní oprávnění pro aplikace, které potřebují plný přístup k souborovému systému (správci souborů, nástroje pro zálohování). Žádost o oprávnění otevře systémovou obrazovku s varováním pro uživatele. Při publikování v Google Play je nutné vyplnit formulář Declaration o nezbytnosti tohoto oprávnění.

Jak získat cestu k souboru z content URI v Scoped Storage?

V Scoped Storage na Android 11+ nelze získat přímou cestu k souboru z content URI. Místo toho použijte ContentResolver.openInputStream() pro čtení a openOutputStream() pro zápis. Pokud potřebujete cestu k souboru pro kompatibilitu s knihovnou třetí strany — vytvořte kopii souboru v getCacheDir() a pracujte s kopií.

Jak Scoped Storage ovlivňuje FileProvider?

FileProvider nadále funguje beze změn — používá se k poskytování přístupu k souborům z sandboxu aplikace jiným aplikacím prostřednictvím content URIs. Scoped Storage neovlivňuje FileProvider, protože FileProvider pracuje na úrovni content URIs, nikoli přímých cest k souborům.

Jak zjistit, zda zařízení podporuje Scoped Storage?

Zkontrolujte Build.VERSION.SDK_INT: pokud >= Build.VERSION_CODES.Q (29), zařízení podporuje Scoped Storage. Na Android 10 však může být Scoped Storage deaktivován pomocí requestLegacyExternalStorage. Na Android 11+ zkontrolujte, zda je v manifestu nastaven příznak requestLegacyExternalStorage — pokud ne, Scoped Storage je aktivní.

Shrnutí

  • Scoped Storage — model přístupu k souborům v Android 10+, který omezuje svévolné čtení sdíleného úložiště.
  • Aplikace má plný přístup ke svému soukromému sandboxu bez dalších oprávnění.
  • Pro přístup ke sdíleným mediálním souborům se používá MediaStore API s content URIs.
  • Pro přístup k libovolným souborům a adresářům se používá Storage Access Framework (SAF).
  • Počínaje Android 11 je Scoped Storage povinný pro všechny aplikace.
  • Oprávnění READ_EXTERNAL_STORAGE a WRITE_EXTERNAL_STORAGE nefungují ve většině scénářů na Android 11+.
  • Při migraci nahraďte přímé cesty k souborům pomocí ContentResolver.openInputStream / openOutputStream.

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také