Permitir acesso parcial a fotos e vídeos

O Android 14 lançou o recurso "Acesso a fotos selecionadas", que permite que os usuários concedam aos apps acesso a imagens e vídeos específicos na biblioteca, em vez de conceder acesso a todas as mídias de um determinado tipo.

Essa mudança só será ativada se o app for destinado ao Android 14 (nível 34 da API) ou mais recente. Se você ainda não usa o seletor de fotos, recomendamos implementá-lo no app para oferecer uma experiência consistente de seleção de imagens e vídeos que também melhore a privacidade do usuário sem precisar solicitar nenhuma permissão de armazenamento.

Se você mantiver seu próprio seletor de galeria usando permissões de armazenamento e precisar manter o controle total sobre a implementação, adapte sua implementação para usar a nova permissão READ_MEDIA_VISUAL_USER_SELECTED. Se o app não usar a nova permissão, o sistema vai executá-lo em um modo de compatibilidade.

SDK de destino READ_MEDIA_VISUAL_USER_SELECTED declarado Acesso às fotos selecionado ativado Comportamento de UX
SDK 33 Não Não N/A
Sim Sim Controlado pelo app
SDK 34 Não Sim Controlado pelo sistema (comportamento de compatibilidade)
Sim Sim Controlado pelo app

Criar seu próprio seletor de galeria exige muito desenvolvimento e manutenção, e o app precisa solicitar permissões de armazenamento para receber o consentimento explícito do usuário. Os usuários podem negar essas solicitações ou, se o app estiver sendo executado em um dispositivo com o Android 14 e for direcionado a essa versão (nível 34 da API) ou mais recente, limitar o acesso à mídia selecionada. A imagem a seguir mostra um exemplo de solicitação de permissões e seleção de mídia usando as novas opções.

A extensão .
Figura 1. A nova caixa de diálogo permite que o usuário selecione fotos e vídeos específicos que ele quer disponibilizar para o app, além das opções usuais para conceder acesso total ou negar todo o acesso.

Esta seção demonstra a abordagem recomendada para criar seu próprio seletor de galeria usando MediaStore. Se você já tem um seletor de galeria para seu app e precisa ter controle total, use esses exemplos para adaptar sua implementação. Se você não atualizar a implementação para processar o acesso a fotos selecionadas, o sistema vai executar o app em um modo de compatibilidade.

Solicitar permissões

Primeiro, solicite as permissões de armazenamento corretas no manifesto do Android, dependendo da versão do SO:

<!-- 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" />

Em seguida, solicite as permissões de execução corretas, que também dependem da versão do SO:

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

Alguns apps não precisam de permissões

A partir do Android 10 (nível 29 da API), os apps não precisam mais de permissões de armazenamento para adicionar arquivos ao armazenamento compartilhado. Isso significa que os apps podem adicionar imagens à galeria, gravar vídeos e salvá-los no armazenamento compartilhado ou fazer o download de faturas em PDF sem precisar solicitar permissões de armazenamento. Caso o app adicione apenas arquivos ao armazenamento compartilhado e não consulte imagens ou vídeos, pare de solicitar permissões de armazenamento e defina um maxSdkVersion da API de nível 28 no AndroidManifest.xml:

<!-- 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" />

Processar a nova seleção de mídia

Com o recurso Acesso às fotos selecionadas no Android 14, seu app precisa adotar a nova permissão READ_MEDIA_VISUAL_USER_SELECTED para controlar a nova seleção de mídia e atualizar a interface para permitir que os usuários concedam ao app acesso a um conjunto diferente de imagens e vídeos. A imagem a seguir mostra um exemplo de como solicitar permissões e selecionar novamente a mídia:

A extensão .
Figura 2. A nova caixa de diálogo também permite que o usuário selecione novamente as fotos e os vídeos que ele quer disponibilizar para o app.

Ao abrir a caixa de diálogo de seleção, fotos, vídeos ou ambos são exibidos, dependendo das permissões solicitadas. Por exemplo, se você solicitar a permissão READ_MEDIA_VIDEO sem a READ_MEDIA_IMAGES, apenas vídeos vão aparecer na interface para que os usuários selecionem arquivos.

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

É possível verificar se o app tem acesso total, parcial ou negado à biblioteca de fotos do dispositivo e atualizar a interface de acordo. Solicite essas permissões quando o app precisar de acesso ao armazenamento, em vez de na inicialização. A concessão de permissão pode ser alterada entre os callbacks do ciclo de vida do app onStart e onResume, já que o usuário pode mudar o acesso nas configurações sem fechar o app.

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
}

Consultar a biblioteca de dispositivos

Depois de verificar se você tem acesso às permissões de armazenamento corretas, interaja com MediaStore para consultar a biblioteca do dispositivo. A mesma abordagem funciona seja o acesso concedido parcial ou total:

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
}

Este snippet de código foi simplificado para ilustrar como interagir com MediaStore. Em um app pronto para produção, use a paginação com algo como a biblioteca Paging para garantir um bom desempenho.

Consultar a última seleção

Os apps no Android 15 e mais recentes e no Android 14 com suporte a atualizações do sistema do Google Play podem consultar a última seleção de imagens e vídeos feita pelo usuário no acesso parcial ativando o QUERY_ARG_LATEST_SELECTION_ONLY:

if (getExtensionVersion(Build.VERSION_CODES.U) >= 12) {
    val queryArgs = bundleOf(
        QUERY_ARG_SQL_SORT_ORDER to "${Images.Media.DATE_ADDED} DESC"
        QUERY_ARG_LATEST_SELECTION_ONLY to true
    )

    contentResolver.query(collectionUri, projection, queryArgs, null)
}

O acesso a fotos e vídeos é preservado quando o dispositivo é atualizado

Nos casos em que o app está em um dispositivo que faz o upgrade de uma versão anterior para o Android 14, o sistema mantém acesso total às fotos e aos vídeos do usuário, além de conceder ao app algumas permissões automaticamente. O comportamento exato depende do conjunto de permissões concedidas ao app antes do upgrade do dispositivo para o Android 14.

Permissões do Android 13

Considere esta situação:

  1. O app é instalado em um dispositivo com o Android 13.
  2. O usuário concedeu as permissões READ_MEDIA_IMAGES e READ_MEDIA_VIDEO ao app.
  3. O dispositivo é atualizado para o Android 14 enquanto o app ainda está instalado.
  4. O app começa a ser destinado ao Android 14 (nível 34 da API) ou versões mais recentes.

Nesse caso, o app ainda terá acesso total aos vídeos e fotos do usuário. O sistema também mantém automaticamente as permissões READ_MEDIA_IMAGES e READ_MEDIA_VIDEO concedidas ao app.

Permissões do Android 12 e versões anteriores

Considere esta situação:

  1. O app é instalado em um dispositivo com o Android 13.
  2. O usuário concedeu a permissão READ_EXTERNAL_STORAGE ou WRITE_EXTERNAL_STORAGE ao app.
  3. O dispositivo é atualizado para o Android 14 enquanto o app ainda está instalado.
  4. O app começa a ser destinado ao Android 14 (nível 34 da API) ou versões mais recentes.

Nesse caso, o app ainda terá acesso total aos vídeos e fotos do usuário. O sistema também concede automaticamente as permissões READ_MEDIA_IMAGES e READ_MEDIA_VIDEO ao app.

Práticas recomendadas

Esta seção contém várias práticas recomendadas para usar a permissão READ_MEDIA_VISUAL_USER_SELECTED. Para mais informações, confira nossas práticas recomendadas de permissões.

Não armazenar o estado da permissão permanentemente

Não armazene o estado de permissão de modo permanente, incluindo SharedPreferences ou DataStore. O estado armazenado pode não estar sincronizado com o estado real. O estado de permissão pode mudar após a redefinição da permissão, a hibernação do app, uma mudança iniciada pelo usuário nas configurações do app ou quando o app fica em segundo plano. Em vez disso, confira as permissões de armazenamento usando ContextCompat.checkSelfPermission().

Não ter acesso total a fotos e vídeos

Com base nas mudanças apresentadas no Android 14, o app pode ter acesso parcial à biblioteca de fotos do dispositivo. Se o app estiver armazenando dados MediaStore em cache quando eles são consultados com ContentResolver, talvez o cache não esteja atualizado.

  • Sempre consulte MediaStore usando ContentResolver em vez de depender de um cache armazenado.
  • Mantenha os resultados na memória enquanto o app estiver em primeiro plano.
  • Atualize os resultados quando o app passar pelo ciclo de vida onResume, porque o usuário pode alternar do acesso total para o parcial usando as configurações de permissão.

Tratar o acesso ao URI como temporário

Se o usuário escolher Selecionar fotos e vídeos na caixa de diálogo de permissões do sistema, o acesso do app aos vídeos e fotos selecionados vai expirar. Seu app precisa sempre processar o caso de não ter acesso a nenhuma Uri, independente da autoridade.

Filtrar o tipo de mídia selecionável por permissão

A caixa de diálogo de seleção depende do tipo de permissão solicitada:

  • Solicitar apenas READ_MEDIA_IMAGES mostra apenas imagens que podem ser selecionadas.
  • Solicitar apenas READ_MEDIA_VIDEO mostra apenas o vídeo como selecionável.
  • Solicitar READ_MEDIA_IMAGES e READ_MEDIA_VIDEO faz com que toda a biblioteca de fotos seja selecionável.

Com base nos casos de uso do app, solicite as permissões corretas para evitar uma experiência ruim do usuário. Se um recurso espera apenas que os vídeos sejam selecionados, solicite apenas READ_MEDIA_VIDEO.

Solicitar permissões em uma única operação

Para evitar que os usuários recebam várias caixas de diálogo do ambiente de execução do sistema, solicite as permissões READ_MEDIA_VISUAL_USER_SELECTED, ACCESS_MEDIA_LOCATION e "ler mídia" (READ_MEDIA_IMAGES, READ_MEDIA_VIDEO ou ambas) em uma única operação.

Permitir que os usuários gerenciem a seleção

Quando o usuário escolher o modo de acesso parcial, o app não poderá presumir que a biblioteca de fotos do dispositivo está vazia e precisará permitir que o usuário conceda mais arquivos.

O usuário pode decidir alternar do acesso total para o parcial usando as configurações de permissão sem conceder acesso a alguns arquivos de mídia visual.

Modo de compatibilidade

Se você mantiver seu próprio seletor de galeria usando permissões de armazenamento, mas não adaptar o app para usar a nova permissão READ_MEDIA_VISUAL_USER_SELECTED, o sistema vai executar o app em um modo de compatibilidade sempre que o usuário precisar selecionar ou selecionar novamente a mídia.

Comportamento durante a seleção inicial de mídia

Durante a seleção inicial, se um usuário escolher "Selecionar fotos e vídeos" (consulte Figura 1), as permissões READ_MEDIA_IMAGES e READ_MEDIA_VIDEO serão concedidas durante a sessão do app, fornecendo uma permissão temporária e acesso temporário aos vídeos e fotos selecionados pelo usuário. Quando seu app passa para o segundo plano ou quando o usuário encerra o app, o sistema nega essas permissões. Esse comportamento é igual ao de outras permissões únicas.

Comportamento durante a reclassificação de mídia

Se o app precisar acessar outras fotos e vídeos mais tarde, será necessário solicitar manualmente a permissão READ_MEDIA_IMAGES ou READ_MEDIA_VIDEO mais uma vez. O sistema segue o mesmo fluxo da solicitação de permissão inicial, pedindo que os usuários selecionem fotos e vídeos (consulte a Figura 2).

Se o app estiver seguindo as práticas recomendadas de permissões, essa mudança não poderá corromper o app. Isso é especialmente verdadeiro se o app não presumir que o acesso ao URI é mantido, armazenar o estado de permissão do sistema ou atualizar o conjunto de imagens exibidas após a mudança da permissão. No entanto, esse comportamento pode não ser ideal, dependendo do caso de uso do app. Para oferecer a melhor experiência aos usuários, recomendamos implementar o seletor de fotos ou adaptar o seletor de galeria do app para processar esse comportamento diretamente usando a permissão READ_MEDIA_VISUAL_USER_SELECTED.