Przyznaj częściowy dostęp do zdjęć i filmów

Android 14 wprowadza dostęp do wybranych zdjęć, który pozwala przyznawać aplikacjom dostęp do określonych obrazów i filmów w bibliotece, zamiast przyznawać dostęp do wszystkich multimediów danego typu.

Ta zmiana jest włączona tylko wtedy, gdy Twoja aplikacja jest kierowana na Androida 14 (poziom API 34) lub nowszego. Jeśli nie używasz jeszcze selektora zdjęć, zalecamy zaimplementowanie go w swojej aplikacji. Pozwoli to w spójny sposób wybierać obrazy i filmy, a jednocześnie zwiększy prywatność użytkowników bez konieczności wysyłania próśb o uprawnienia do przechowywania danych.

Jeśli samodzielnie zarządzasz selektorem galerii z użyciem uprawnień do przechowywania danych i chcesz zachować pełną kontrolę nad implementacją, dostosuj implementację, aby wykorzystywała nowe uprawnienie READ_MEDIA_VISUAL_USER_SELECTED. Jeśli aplikacja nie korzysta z nowych uprawnień, system uruchomi ją w trybie zgodności.

Docelowy pakiet SDK Zadeklarowano READ_MEDIA_VISUAL_USER_SELECTED Dostęp do wybranych zdjęć włączony Sposób działania
Pakiet SDK 33 Nie Nie Nie dotyczy
Tak Tak Kontrolowane przez aplikację
Pakiet SDK 34 Nie Tak Kontrolowane przez system (zachowanie zgodności)
Tak Tak Kontrolowane przez aplikację

Utworzenie własnego selektora galerii wymaga intensywnego programowania i konserwacji, a aplikacja musi prosić o uprawnienia do przechowywania danych, aby uzyskać wyraźną zgodę użytkownika. Użytkownicy mogą odrzucać te żądania. Jeśli aplikacja działa na urządzeniach z Androidem 14 i jest kierowana na Androida w wersji 14 (poziom API 34) lub nowszej, można ograniczyć dostęp do wybranych multimediów. Poniższy przykład przedstawia przykład wysyłania prośby o uprawnienia i wybierania multimediów za pomocą nowych opcji.

Format
Rysunek 1. Nowe okno pozwala użytkownikowi wybrać konkretne zdjęcia i filmy, które chce udostępnić swojej aplikacji, oprócz standardowych opcji przyznania pełnego dostępu lub odmowy dostępu do niego.

W tej sekcji przedstawiamy zalecane podejście do tworzenia własnego selektora galerii za pomocą komponentu MediaStore. Jeśli masz już selektor galerii w swojej aplikacji i chcesz zachować pełną kontrolę, możesz skorzystać z tych przykładów, aby dostosować implementację. Jeśli nie zaktualizujesz implementacji, aby obsługiwała dostęp do wybranych zdjęć, system uruchomi Twoją aplikację w trybie zgodności.

Poproś o uprawnienia

Najpierw poproś o odpowiednie uprawnienia do przechowywania danych w pliku manifestu Androida w zależności od wersji systemu operacyjnego:

<!-- Devices running Android 12L (API level 32) or lower  -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />

<!-- Devices running Android 13 (API level 33) or higher -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />

<!-- To handle the reselection within the app on devices running Android 14
     or higher if your app targets Android 14 (API level 34) or higher.  -->
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />

Następnie poproś o odpowiednie uprawnienia w czasie działania, także w zależności od wersji systemu operacyjnego:

// Register ActivityResult handler
val requestPermissions = registerForActivityResult(RequestMultiplePermissions()) { results ->
    // Handle permission requests results
    // See the permission example in the Android platform samples: https://github.com/android/platform-samples
}

// Permission request logic
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
    requestPermissions.launch(arrayOf(READ_MEDIA_IMAGES, READ_MEDIA_VIDEO, READ_MEDIA_VISUAL_USER_SELECTED))
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
    requestPermissions.launch(arrayOf(READ_MEDIA_IMAGES, READ_MEDIA_VIDEO))
} else {
    requestPermissions.launch(arrayOf(READ_EXTERNAL_STORAGE))
}

Niektóre aplikacje nie wymagają uprawnień

Od Androida 10 (poziom interfejsu API 29) aplikacje nie potrzebują już uprawnień do zapisywania plików w pamięci współdzielonej. Oznacza to, że aplikacje mogą dodawać obrazy do galerii, nagrywać filmy i zapisywać je w pamięci współdzielonej oraz pobierać faktury w formacie PDF bez konieczności wysyłania próśb o uprawnienia do przechowywania danych. Jeśli Twoja aplikacja dodaje pliki tylko do pamięci współdzielonej i nie wysyła zapytań dotyczących obrazów ani filmów, wyłącz w AndroidManifest.xml prośbę o uprawnienia do przechowywania danych i ustaw maxSdkVersion z interfejsem API 28:

<!-- No permission is needed to add files to shared storage on Android 10 (API level 29) or higher  -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="28" />

Obsługa ponownego wyboru multimediów

Dzięki funkcji dostępu do wybranych zdjęć w Androidzie 14 aplikacja powinna stosować nowe uprawnienie READ_MEDIA_VISUAL_USER_SELECTED, które umożliwia sterowanie ponownym wybieraniem multimediów, oraz aktualizować interfejs aplikacji tak, aby użytkownicy mogli przyznawać jej dostęp do innego zestawu obrazów i filmów. Poniższy obraz przedstawia przykład prośby o uprawnienia i ponownego wyboru multimediów:

Format
Rysunek 2. Nowe okno pozwala też użytkownikowi ponownie wybrać zdjęcia i filmy, które chce udostępnić Twojej aplikacji.

Po otwarciu okna wyboru wyświetlane są zdjęcia, filmy lub oba te elementy w zależności od wymaganych uprawnień. Jeśli na przykład prosisz o uprawnienie READ_MEDIA_VIDEO bez uprawnienia READ_MEDIA_IMAGES, w interfejsie będą wyświetlane tylko filmy, które użytkownicy będą mogli wybrać.

// Allow the user to select only videos
requestPermissions.launch(arrayOf(READ_MEDIA_VIDEO, READ_MEDIA_VISUAL_USER_SELECTED))

Możesz sprawdzić, czy aplikacja ma pełny, częściowy lub zabroniony dostęp do biblioteki zdjęć na urządzeniu, i odpowiednio zaktualizować interfejs. Żądaj tych uprawnień, gdy aplikacja potrzebuje dostępu do pamięci, a nie podczas uruchamiania. Pamiętaj, że przyznane uprawnienia można zmieniać między wywołaniami zwrotnymi cyklu życia aplikacji onStart i onResume, ponieważ użytkownik może zmienić dostęp w ustawieniach bez zamykania aplikacji.

if (
    Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
    (
        ContextCompat.checkSelfPermission(context, READ_MEDIA_IMAGES) == PERMISSION_GRANTED ||
        ContextCompat.checkSelfPermission(context, READ_MEDIA_VIDEO) == PERMISSION_GRANTED
    )
) {
    // Full access on Android 13 (API level 33) or higher
} else if (
    Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE &&
    ContextCompat.checkSelfPermission(context, READ_MEDIA_VISUAL_USER_SELECTED) == PERMISSION_GRANTED
) {
    // Partial access on Android 14 (API level 34) or higher
}  else if (ContextCompat.checkSelfPermission(context, READ_EXTERNAL_STORAGE) == PERMISSION_GRANTED) {
    // Full access up to Android 12 (API level 32)
} else {
    // Access denied
}

Tworzenie zapytania do biblioteki urządzeń

Gdy potwierdzisz, że masz odpowiednie uprawnienia dostępu do pamięci, możesz wykonywać działania w MediaStore, aby wysyłać zapytania do biblioteki urządzeń (ta sama metoda działa niezależnie od tego, czy został przyznany dostęp częściowy czy pełny):

data class Media(
    val uri: Uri,
    val name: String,
    val size: Long,
    val mimeType: String,
)

// Run the querying logic in a coroutine outside of the main thread to keep the app responsive.
// Keep in mind that this code snippet is querying only images of the shared storage.
suspend fun getImages(contentResolver: ContentResolver): List<Media> = withContext(Dispatchers.IO) {
    val projection = arrayOf(
        Images.Media._ID,
        Images.Media.DISPLAY_NAME,
        Images.Media.SIZE,
        Images.Media.MIME_TYPE,
    )

    val collectionUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        // Query all the device storage volumes instead of the primary only
        Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL)
    } else {
        Images.Media.EXTERNAL_CONTENT_URI
    }

    val images = mutableListOf<Media>()

    contentResolver.query(
        collectionUri,
        projection,
        null,
        null,
        "${Images.Media.DATE_ADDED} DESC"
    )?.use { cursor ->
        val idColumn = cursor.getColumnIndexOrThrow(Images.Media._ID)
        val displayNameColumn = cursor.getColumnIndexOrThrow(Images.Media.DISPLAY_NAME)
        val sizeColumn = cursor.getColumnIndexOrThrow(Images.Media.SIZE)
        val mimeTypeColumn = cursor.getColumnIndexOrThrow(Images.Media.MIME_TYPE)

        while (cursor.moveToNext()) {
            val uri = ContentUris.withAppendedId(collectionUri, cursor.getLong(idColumn))
            val name = cursor.getString(displayNameColumn)
            val size = cursor.getLong(sizeColumn)
            val mimeType = cursor.getString(mimeTypeColumn)

            val image = Media(uri, name, size, mimeType)
            images.add(image)
        }
    }

    return@withContext images
}

Ten fragment kodu został uproszczony, aby pokazać, jak korzystać z komponentu MediaStore. Aby zapewnić wysoką wydajność aplikacji w wersji produkcyjnej, użyj podziału na strony, np. biblioteki stron docelowych.

Dostęp do zdjęć i filmów zostanie zachowany po uaktualnieniu urządzenia

Jeśli Twoja aplikacja znajduje się na urządzeniu, które zostanie zaktualizowane ze starszej wersji Androida na Androida 14, system zachowuje pełny dostęp do zdjęć i filmów użytkownika oraz automatycznie przyznaje aplikacji niektóre uprawnienia. Dokładne działanie zależy od zestawu uprawnień przyznanych aplikacji przed aktualizacją urządzenia do Androida 14.

Uprawnienia z Androida 13

Weź pod uwagę następującą sytuację:

  1. Aplikacja jest zainstalowana na urządzeniu z Androidem 13.
  2. Użytkownik przyznał Twojej aplikacji uprawnienia READ_MEDIA_IMAGES i READ_MEDIA_VIDEO.
  3. Urządzenie zostanie zaktualizowane do Androida 14, a aplikacja będzie nadal zainstalowana.
  4. Twoja aplikacja zacznie być kierowana na Androida 14 (poziom API 34) lub nowszego.

W takim przypadku aplikacja nadal ma pełny dostęp do zdjęć i filmów użytkownika. System automatycznie zachowuje też uprawnienia READ_MEDIA_IMAGES i READ_MEDIA_VIDEO.

Uprawnienia w Androidzie 12 i starszych

Weź pod uwagę następującą sytuację:

  1. Aplikacja jest zainstalowana na urządzeniu z Androidem 13.
  2. Użytkownik przyznał Twojej aplikacji uprawnienia READ_EXTERNAL_STORAGE lub WRITE_EXTERNAL_STORAGE.
  3. Urządzenie zostanie zaktualizowane do Androida 14, a aplikacja będzie nadal zainstalowana.
  4. Twoja aplikacja zacznie być kierowana na Androida 14 (poziom API 34) lub nowszego.

W takim przypadku aplikacja nadal ma pełny dostęp do zdjęć i filmów użytkownika. System automatycznie przyznaje też Twojej aplikacji uprawnienia READ_MEDIA_IMAGES i READ_MEDIA_VIDEO.

Sprawdzone metody

Ta sekcja zawiera kilka sprawdzonych metod korzystania z uprawnienia READ_MEDIA_VISUAL_USER_SELECTED. Aby dowiedzieć się więcej, zapoznaj się z naszymi sprawdzonymi metodami uzyskiwania uprawnień.

Nie zapisuj stanu uprawnień na stałe

Nie zapisuj na stałe stanu uprawnień, np. SharedPreferences czy DataStore. Zapisany stan może nie być zsynchronizowany z rzeczywistym. Stan uprawnień może się zmienić po zresetowaniu uprawnień, hibernacji aplikacji, wywołaniu przez użytkownika zmiany w ustawieniach aplikacji lub po uruchomieniu aplikacji w tle. W takim przypadku sprawdź uprawnienia do pamięci za pomocą metody ContextCompat.checkSelfPermission().

Nie zakładaj pełnego dostępu do zdjęć i filmów

Ze względu na zmiany wprowadzone w Androidzie 14 Twoja aplikacja może mieć tylko częściowy dostęp do biblioteki zdjęć na urządzeniu. Jeśli aplikacja przechowuje dane MediaStore w pamięci podręcznej po wysłaniu zapytania z użyciem ContentResolver, pamięć podręczna może nie być aktualna.

  • Zawsze wykonuj zapytania MediaStore za pomocą ContentResolver, zamiast korzystać z przechowywanej pamięci podręcznej.
  • Przechowuj wyniki w pamięci, gdy aplikacja działa na pierwszym planie.
  • Odśwież wyniki, gdy aplikacja będzie przechodzić przez cykl życia aplikacji onResume, ponieważ użytkownik może zmienić dostęp z pełnego na częściowy w ustawieniach uprawnień.

Traktuj dostęp do identyfikatora URI jako tymczasowy

Jeśli w oknie uprawnień systemowych użytkownik wybierze Wybierz zdjęcia i filmy, dostęp aplikacji do wybranych zdjęć i filmów wygaśnie. Aplikacja powinna zawsze obsługiwać zgłoszenia w sytuacji, gdy nie ma dostępu do żadnych elementów Uri, bez względu na ich uprawnienia.

Filtruj typ multimediów do wyboru według uprawnień

Okno wyboru dotyczy żądanego typu uprawnień:

  • Żądanie dotyczące tylko wartości READ_MEDIA_IMAGES spowoduje wyświetlenie tylko obrazów do wyboru.
  • Jeśli poprosisz tylko o ustawienie READ_MEDIA_VIDEO, zobaczysz tylko film do wyboru.
  • Gdy wyślesz żądanie READ_MEDIA_IMAGES i READ_MEDIA_VIDEO, możesz wybrać całą bibliotekę zdjęć.

W zależności od przypadków użycia swojej aplikacji musisz zadbać o odpowiednie uprawnienia, aby zadbać o wrażenia użytkowników. Jeśli funkcja wymaga tylko wybrania filmów, pamiętaj, aby prosić tylko o READ_MEDIA_VIDEO.

Wysyłanie prośby o uprawnienia w ramach jednej operacji

Aby użytkownicy nie widzieli kilku okien dialogowych w czasie działania systemu, poproś o uprawnienia READ_MEDIA_VISUAL_USER_SELECTED, ACCESS_MEDIA_LOCATION i „Odczyt multimediów” (READ_MEDIA_IMAGES, READ_MEDIA_VIDEO lub oba) w ramach jednej operacji.

Zezwalaj użytkownikom na zarządzanie wyborem

Gdy użytkownik wybierze tryb częściowego dostępu, aplikacja nie powinna zakładać, że biblioteka zdjęć na urządzeniu jest pusta, i zezwolić mu na udostępnianie większej liczby plików.

Użytkownik może w ustawieniach uprawnień przejść z pełnego dostępu na częściowy dostęp bez przyznawania dostępu do niektórych plików multimediów wizualnych.

Tryb zgodności

Jeśli utrzymujesz własny selektor galerii z użyciem uprawnień do przechowywania danych, ale nie dostosowałeś aplikacji do korzystania z nowego uprawnienia READ_MEDIA_VISUAL_USER_SELECTED, system uruchamia Twoją aplikację w trybie zgodności za każdym razem, gdy użytkownik chce wybrać lub ponownie wybrać multimedia.

Zachowanie przy początkowym wyborze multimediów

Jeśli podczas początkowego wyboru użytkownik wybierze opcję „Wybierz zdjęcia i filmy” (zobacz rysunek 1), podczas sesji w aplikacji zostaną przyznane uprawnienia READ_MEDIA_IMAGES i READ_MEDIA_VIDEO oraz tymczasowy dostęp do wybranych przez użytkownika zdjęć i filmów. Gdy aplikacja przełączy się w tle lub użytkownik aktywnie ją wyłącza, system w końcu unieważni te uprawnienia. Działa to tak samo jak w przypadku innych uprawnień jednorazowych.

Zachowanie podczas ponownego wyboru multimediów

Jeśli w przyszłości Twoja aplikacja będzie potrzebować dostępu do dodatkowych zdjęć i filmów, musisz jeszcze raz ręcznie poprosić o uprawnienie READ_MEDIA_IMAGES lub READ_MEDIA_VIDEO. System przebiega tak samo jak w przypadku początkowej prośby o przyznanie uprawnień, prosząc użytkowników o wybranie zdjęć i filmów (patrz ilustracja 2).

Jeśli Twoja aplikacja jest zgodna ze sprawdzonymi metodami dotyczącymi uprawnień, ta zmiana nie powinna jej spowodować. Zwłaszcza jeśli aplikacja nie zakłada, że dostęp do identyfikatora URI jest zachowywana, przechowuje stan uprawnień systemowych, nie odświeża zestawu wyświetlanych obrazów po zmianie uprawnień. Jednak w zależności od zastosowania aplikacji takie działanie może nie być idealne. Aby zapewnić użytkownikom jak najlepsze wrażenia, zalecamy wdrożenie selektora zdjęć lub dostosowanie selektora galerii w aplikacji tak, aby bezpośrednio obsługiwał to działanie za pomocą uprawnienia READ_MEDIA_VISUAL_USER_SELECTED.