Storage Access Framework — to framework Androida do bezpiecznego dostępu do plików i dokumentów za pomocą systemowego okna wyboru. Zamiast żądania szerokich uprawnień do odczytu pamięci, aplikacja otrzymuje URI-odnośnik do pliku wybranego przez użytkownika. Według Android Developers (2026), SAF obsługuje pamięć lokalną, usługi w chmurze Google Drive i Dropbox przez DocumentProvider. Framework został wprowadzony w Android 4.4 i stał się standardem pracy z dokumentami od Android 10.
Najważniejsze
Storage Access Framework — to część Android SDK, która zapewnia jednolity interfejs do wyboru i tworzenia dokumentów za pomocą systemowego okna dialogowego. SAF abstrahuje fizyczną lokalizację plików: aplikacja nie wie, skąd odczytywany jest plik — z dysku lokalnego, Google Drive czy Dropbox.
Architektura SAF obejmuje trzy komponenty: aplikację kliencką, która inicjuje żądanie, systemowy wybór plików — standardowe okno dialogowe wyboru pliku, oraz DocumentProvider — dostawcę treści implementującego dostęp do plików konkretnego magazynu. Użytkownik widzi jednolity interfejs niezależnie od źródła danych.
SAF jest dostępny od Android 4.4 (API 19). Początkowo framework obsługiwał tylko dokumenty, ale w Android 5.0 dodano obsługę katalogów przez ACTION_OPEN_DOCUMENT_TREE. Od Android 10 SAF stał się zalecanym sposobem dostępu do dowolnego pliku poza app-specific storage.
SAF uruchamia systemowe okno wyboru pliku przez Intent z akcją ACTION_OPEN_DOCUMENT. Użytkownik widzi listę dostępnych źródeł: pamięć wewnętrzną, Google Drive, Dropbox i innych zarejestrowanych dostawców. Po wybraniu pliku system zwraca content URI z tymczasowymi prawami dostępu.
Content URI ma format content://com.android.externalstorage.documents/document/primary/Download/file.pdf. W przeciwieństwie do file:// URI, content URI nie ujawnia rzeczywistej ścieżki do pliku i działa przez DocumentProvider. Aplikacja odczytuje plik przez ContentResolver.openInputStream na podstawie otrzymanego URI.
Systemowy wybór plików automatycznie obsługuje wyszukiwanie, sortowanie i filtrowanie plików według typów MIME. Deweloper określa potrzebne typy przez Intent.putExtra(Intent.EXTRA_MIME_TYPES, arrayOf("application/pdf", "image/*")), a wybór plików pokazuje tylko odpowiednie pliki.
Domyślnie URI jest ważny do ponownego uruchomienia aplikacji lub restartu urządzenia. Długoterminowy dostęp aplikacja uzyskuje przez takePersistableUriPermission — to pozwala odczytywać plik przy kolejnych uruchomieniach bez ponownego wyboru przez okno dialogowe.
SAF udostępnia trzy główne akcje do pracy z plikami: otwieranie, tworzenie i wybór drzewa folderów. ACTION_OPEN_DOCUMENT otwiera systemowy wybór plików do wyboru istniejącego pliku. ACTION_CREATE_DOCUMENT tworzy nowy plik — użytkownik wpisuje nazwę w oknie dialogowym, a aplikacja otrzymuje URI do zapisu.
ACTION_OPEN_DOCUMENT_TREE pozwala wybrać cały katalog i uzyskać dostęp do wszystkich plików w nim. Jest to używane w menedżerach plików, aplikacjach do tworzenia kopii zapasowych i synchronizacji. Aplikacja otrzymuje URI katalogu i może rekurencyjnie przeglądać zawartość przez DocumentFile.
| Akcja | Przeznaczenie | Flaga |
|---|---|---|
| ACTION_OPEN_DOCUMENT | Wybór istniejącego pliku | READ_FLAG |
| ACTION_CREATE_DOCUMENT | Tworzenie nowego pliku | WRITE_FLAG |
| ACTION_OPEN_DOCUMENT_TREE | Wybór katalogu | READ + WRITE |
Dla każdej akcji określane są typy MIME przez EXTRA_MIME_TYPES. Można podać kilka typów: "application/pdf", "image/*", "text/plain". Jeśli typy nie są określone, wybór plików pokazuje wszystkie pliki.
Persistent URI permissions — mechanizm SAF, który pozwala zachować dostęp do pliku po zakończeniu bieżącej sesji. Bez tej flagi URI jest ważny tylko do ponownego uruchomienia aplikacji. Aplikacja żąda flagi FLAG_GRANT_PERSISTABLE_URI_PERMISSION wraz z flagami READ i WRITE.
Do zachowania uprawnień używana jest metoda ContentResolver.takePersistableUriPermission. System przechowuje URI w specjalnym rejestrze i przywraca dostęp przy następnym uruchomieniu aplikacji. Aby sprawdzić, czy aplikacja ma trwały dostęp do URI, używana jest ContentResolver.persistedUriPermissions.
Użytkownik może cofnąć zachowane uprawnienia przez Ustawienia → Aplikacje → Uprawnienia. Aplikacja powinna obsługiwać scenariusz, gdy dostęp do pliku niespodziewanie zniknie. Zaleca się sprawdzanie dostępu przez ContentResolver.openInputStream przed rozpoczęciem pracy i prawidłowe obsługiwanie SecurityException.
SAF uruchamiany jest przez standardowy Intent. Kod jest minimalny: utwórz Intent z ACTION_OPEN_DOCUMENT, określ typy MIME i uruchom przez ActivityResultContracts.StartActivityForResult. Po wybraniu pliku callback otrzymuje URI w data.data, który następnie jest używany do odczytu.
val pickFile = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
result.data?.data?.let { uri ->
val inputStream = contentResolver?.openInputStream(uri)
// read from inputStream
}
}
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
setType("application/pdf")
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
}
pickFile.launch(intent)
Do zapisu nowego pliku użyj ACTION_CREATE_DOCUMENT. Intent przyjmuje typ MIME i nazwę pliku przez EXTRA_TITLE. Po wybraniu folderu i potwierdzeniu użytkownik zwraca URI, do którego aplikacja zapisuje dane przez ContentResolver.openOutputStream. System automatycznie tworzy plik w wybranej lokalizacji.
SAF różni się od tradycyjnego READ_EXTERNAL_STORAGE zasadniczo innym podejściem do bezpieczeństwa. Zamiast żądania dostępu do całej pamięci "jednym zamachem", SAF żąda dostępu tylko do konkretnego pliku. Minimalizuje to powierzchnię ataku i zwiększa zaufanie użytkownika.
READ_EXTERNAL_STORAGE daje dostęp do wszystkich plików na urządzeniu, w tym zdjęć i dokumentów innych aplikacji. Na Android 10+ to podejście jest ograniczone. SAF natomiast udostępnia dostęp tylko do wybranego przez użytkownika pliku i wymaga wyraźnego potwierdzenia dla każdego pliku. Do pracy wsadowej z mediami używaj MediaStore, do pojedynczych dokumentów — SAF.
Główną wadą SAF jest konieczność wyboru każdego pliku osobno. Do masowych operacji (kopie zapasowe, synchronizacja folderów) używane jest ACTION_OPEN_DOCUMENT_TREE, który daje dostęp do wszystkich plików w wybranym katalogu. Rozwiązanie zależy od scenariusza: SAF jest optymalny do wyboru przez użytkownika, MediaStore — do programowego dostępu do mediów.
Często zadawane pytania
Storage Access Framework — to framework Androida do bezpiecznego dostępu do plików przez systemowe okno wyboru. Aplikacja otrzymuje content URI do wybranego pliku bez żądania szerokich uprawnień do odczytu pamięci.
Utwórz Intent z ACTION_OPEN_DOCUMENT, określ typ MIME przez setType i uruchom przez ActivityResultContracts. W callback otrzymaj URI z data.data i czytaj przez ContentResolver.openInputStream.
Persistent URI permissions — to mechanizm zachowania dostępu do URI po ponownym uruchomieniu aplikacji. Żądany przez flagę FLAG_GRANT_PERSISTABLE_URI_PERMISSION i metodę takePersistableUriPermission.
SAF obsługuje dowolne typy MIME: application/pdf, image/*, text/plain, application/zip i inne. Typy określa się przez Intent.putExtra z tablicą EXTRA_MIME_TYPES.
SAF przeznaczony jest do wyboru pojedynczych plików przez użytkownika za pomocą systemowego okna dialogowego. MediaStore zapewnia programowy dostęp do wszystkich plików multimedialnych urządzenia przez bazę multimediów bez udziału użytkownika.
Podsumowanie
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.
Przeczytaj również