1. Introdução
O que você vai aprender
- Por que a privacidade está se tornando cada vez mais importante para os usuários.
- Práticas recomendadas sobre privacidade nas versões mais recentes do Android.
- Como integrar essas práticas recomendadas aos seus apps para preservar ainda mais a privacidade dos usuários.
O que você vai criar
Neste codelab, você vai começar com um app de exemplo que permite que os usuários salvem recordações.
Ele vai começar com estas telas:
- Tela de permissões: solicita que o usuário conceda todas as permissões antes de acessar a tela inicial.
- Tela inicial: mostra todos os registros de fotos do usuário e também permite adicionar novas fotos.
- Tela de adição de registro: permite ao usuário criar um novo registro de fotos. Nela, os usuários podem procurar fotos na biblioteca, tirar uma foto nova com a câmera e adicionar a cidade atual ao registro.
- Tela da câmera: permite ao usuário tirar uma foto e salvá-la no registro de fotos.
O app está funcionando, mas tem muitos problemas de privacidade que vão ser corrigidos.
Durante o codelab, você vai aprender:
- Por que a privacidade é importante para seus apps.
- Sobre os recursos de privacidade do Android e as principais práticas recomendadas.
- Como implementar essas práticas recomendadas em um app fazendo o seguinte:
- Solicitando permissões no contexto.
- Reduzir o acesso do app à localização.
- Usar o seletor de fotos e outras melhorias de armazenamento.
- Usando as APIs de auditoria de acesso a dados.
Quando terminar, você vai ter um app que:
- Implementa as práticas recomendadas de privacidade listadas acima.
- Protege a privacidade e os usuários processando os dados particulares deles com cuidado, o que aprimora a experiência do usuário.
O que é necessário
Opcional
- Familiaridade com os componentes da arquitetura, como o ViewModel e a arquitetura sugerida no Guia para a arquitetura do app.
- Familiaridade com o Jetpack Compose. Para uma introdução a este recurso, consulte o Tutorial do Jetpack Compose.
2. Por que a privacidade é importante?
As pesquisas mostram que as pessoas ficam desconfiadas em relação à privacidade. Uma pesquisa realizada pelo Pew Research Institute (link em inglês) descobriu que 84% dos americanos sentem que têm pouco ou nenhum controle sobre os dados coletados por eles ou por empresas e apps. A principal frustração deles é não saber o que acontece com os dados fora do uso direto. Por exemplo, eles temem que os dados sejam usados para outras finalidades, como criar perfis para anúncios segmentados, ou até mesmo vendidos para outras partes. E quando os dados são gerados, parece não haver como removê-los.
Essa preocupação com a privacidade já está afetando significativamente as decisões das pessoas sobre quais serviços ou apps usar. Na verdade, o mesmo estudo do Pew Research Institute descobriu que mais da metade (52%) dos adultos dos EUA decidiram não usar um produto ou serviço devido a questões de privacidade, como a preocupação com a quantidade de dados coletados sobre eles.
Portanto, o aprimoramento e a demonstração da privacidade do app são essenciais para melhorar a experiência dos apps para os usuários. As pesquisas mostram que isso também provavelmente pode ajudar a aumentar sua base de usuários.
Muitos recursos e práticas recomendadas que vamos abordar neste codelab estão diretamente relacionados à redução da quantidade de dados que seu app acessa ou ao aprimoramento do senso de controle dos usuários sobre os dados particulares deles. As duas melhorias tratam diretamente das preocupações que os usuários compartilharam na pesquisa que citamos anteriormente.
3. Configurar o ambiente
Para começar o mais rápido possível, preparamos um projeto inicial para você desenvolver. Nesta etapa, você vai fazer o download do código para o codelab inteiro, incluindo o projeto inicial, e executar o app inicial no emulador ou dispositivo.
Se você tiver o git instalado, basta executar o comando abaixo. Para verificar se o git está instalado, digite git –version
no terminal ou na linha de comando e verifique se ele é executado corretamente.
git clone https://github.com/android/privacy-codelab
Caso você não tenha o git, clique no link para fazer o download de todo o código deste codelab.
Para configurar o codelab, faça o seguinte:
- Abra o projeto no diretório
PhotoLog_Start
no Android Studio. - Execute a configuração de execução
PhotoLog_Start
em um dispositivo ou emulador com o Android 12 (S) ou mais recente.
Você vai encontrar uma tela solicitando permissão para executar o app. Isso significa que você configurou o ambiente.
4. Prática recomendada: solicitar permissões no contexto
A maioria das pessoas sabe que as permissões de execução são essenciais pois desbloqueiam muitas funções importantes para gerar uma boa experiência. Mas você sabia que quando e como o app solicita as permissões também têm um impacto significativo para os usuários?
Vamos conferir como o app PhotoLog_Start
solicita permissões para mostrar por que ele não tem um modelo de permissões ideal:
- Logo após a inicialização, o usuário recebe imediatamente uma solicitação para conceder várias permissões. Isso provavelmente confunde os usuários e faz com que eles percam a confiança no app ou até o desinstalem (na pior das hipóteses).
- O app não permite que os usuários prossigam até que todas as permissões sejam concedidas. Os usuários talvez não confiem no app o suficiente na inicialização para conceder acesso a todas essas informações sensíveis.
Como você provavelmente imaginou, a lista acima representa o conjunto de melhorias que vamos fazer juntos para aprimorar o processo de solicitação de permissão do app. Vamos começar.
As práticas recomendadas do Android dizem que devemos solicitar permissões no contexto na primeira vez que os usuários começam a interagir com um recurso. Isso ocorre porque, se um app solicitar permissão para ativar um recurso com o qual o usuário já está interagindo, a solicitação não será uma surpresa para o usuário. Isso resulta em uma melhor experiência do usuário. No app PhotoLog, precisamos esperar até que os usuários cliquem nos botões de câmera ou de localização pela primeira vez para solicitar permissões.
Primeiro, vamos remover a tela que força os usuários a aprovar todas as permissões antes de acessarem a página inicial. Essa lógica está definida em MainActivity.kt
. Vamos navegar por ela:
val startNavigation = if (permissionManager.hasAllPermissions) { Screens.Home.route } else { Screens.Permissions.route }
Ela verifica se o usuário concedeu todas as permissões antes de permitir que ele acesse a página inicial. Como mencionado antes, isso não segue nossas práticas recomendadas para a experiência do usuário. Vamos usar o código abaixo para mudar isso, permitindo que os usuários interajam com nosso app sem ter todas as permissões concedidas:
val startNavigation = Screens.Home.route
Agora que não precisamos mais da tela de permissões, também podemos excluir esta linha do NavHost:
composable(Screens.Permissions.route) { PermissionScreen(navController) }
Depois, remova esta linha da classe Screens:
object Permissions : Screens("permissions")
Por fim, também podemos excluir o arquivo PermissionsScreen.kt.
Agora exclua e reinstale o app, que é uma maneira de redefinir as permissões concedidas anteriormente. Você pode acessar a tela inicial imediatamente, mas, ao pressionar os botões de câmera ou de localização na tela "Add Log", nada acontece porque o app não tem mais a lógica para solicitar permissões do usuário. Vamos corrigir esse problema.
Adicionar lógica para solicitar a permissão da câmera
Vamos começar com a permissão da câmera. Com base nos exemplos de código mostrados na documentação de solicitação de permissões, vamos registrar o callback de permissões primeiro para usar o contrato RequestPermission()
.
Vamos avaliar a lógica de que precisamos:
- Se o usuário aceitar a permissão, vamos registrar a permissão com o viewModel e navegar até a tela da câmera se o usuário ainda não tiver atingido o limite do número de fotos já adicionadas.
- Se o usuário negar a permissão, vamos informar que o recurso não está funcionando, porque a permissão foi negada.
Para executar essa lógica, podemos adicionar o bloco de código abaixo em: // TODO: Step 1. Register ActivityResult to request Camera permission
val requestCameraPermission = rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted -> if (isGranted) { viewModel.onPermissionChange(CAMERA, isGranted) canAddPhoto { navController.navigate(Screens.Camera.route) } } else { coroutineScope.launch { snackbarHostState.showSnackbar("Camera currently disabled due to denied permission.") } } }
Agora, queremos conferir se o app tem a permissão correta antes de navegar para a tela da câmera e solicitar a permissão dela se o usuário ainda não a tiver concedido. Para implementar essa lógica, podemos adicionar o bloco de código abaixo em: // TODO: Step 2. Check & request for Camera permission before navigating to the camera screen
canAddPhoto { when { state.hasCameraAccess -> navController.navigate(Screens.Camera.route) // TODO: Step 4. Trigger rationale screen for Camera if needed else -> requestCameraPermission.launch(CAMERA) } }
Agora, tente executar o app novamente e clique no ícone da câmera na tela "Add Log". Uma caixa de diálogo que solicita a permissão da câmera vai aparecer. Parabéns! É muito melhor do que pedir para os usuários aprovarem todas as permissões antes mesmo de testarem o app.
Mas podemos melhorar? Sim. Podemos verificar se o sistema recomenda uma justificativa para explicar por que nosso app precisa de acesso à câmera. Isso ajuda a aumentar as taxas de aceitação da permissão e preservar a capacidade dos apps de solicitar a permissão novamente em um momento mais oportuno.
Para fazer isso, vamos criar uma tela de justificativa que explica ao usuário por que nosso app precisa acessar a câmera. Para isso, adicione o bloco de código abaixo em: // TODO: Step 3. Add explanation dialog for Camera permission
var showExplanationDialogForCameraPermission by remember { mutableStateOf(false) } if (showExplanationDialogForCameraPermission) { CameraExplanationDialog( onConfirm = { requestCameraPermission.launch(CAMERA) showExplanationDialogForCameraPermission = false }, onDismiss = { showExplanationDialogForCameraPermission = false }, ) }
Agora que já temos a caixa de diálogo propriamente dita, só precisamos verificar se é necessário mostrar a justificativa antes de solicitar a permissão da câmera. Para fazer isso, chamamos a API shouldShowRequestPermissionRationale()
da ActivityCompat. Se ela retornar "true", defina showExplanationDialogForCameraPermission
como "true" também para mostrar a caixa de diálogo de explicação.
Vamos adicionar o bloco de código abaixo entre os casos state.hasCameraAccess
e else
, ou onde o TODO a seguir foi adicionado anteriormente nas instruções: // TODO: Step 4. Add explanation dialog for Camera permission
.
ActivityCompat.shouldShowRequestPermissionRationale(context.getActivity(), CAMERA) -> showExplanationDialogForCameraPermission = true
A lógica completa do botão da câmera vai ficar assim:
canAddPhoto { when { state.hasCameraAccess -> navController.navigate(Screens.Camera.route) ActivityCompat.shouldShowRequestPermissionRationale(context.getActivity(), CAMERA) -> showExplanationDialogForCameraPermission = true else -> requestCameraPermission.launch(CAMERA) } }
Parabéns! Concluímos o processo de conceder permissão da câmera ao seguir todas as práticas recomendadas do Android. Exclua e reinstale o app novamente e pressione o botão da câmera na página "Add Log". Se você negar a permissão, o app não vai impedir que você use outras funções, como abrir o álbum de fotos.
No entanto, na próxima vez que clicar no ícone da câmera depois de negar a permissão, a solicitação de explicação que acabamos de adicionar vai aparecer novamente.* A solicitação de permissão do sistema só aparece depois que o usuário clica em "continue" na solicitação de explicação. Se o usuário clicar em "not now", vamos permitir que ele use o app sem interrupções. Isso ajuda o app a evitar que o usuário negue a permissão e preserva nossa capacidade de a solicitar novamente em um momento diferente, quando o usuário possa querer conceder a permissão.
- Observação: o comportamento exato da API
shouldShowRequestPermissionRationale()
é um detalhe de implementação interno e está sujeito a mudanças.
Adicionar lógica para solicitar a permissão de localização
Agora, vamos fazer o mesmo para a localização. Primeiro, podemos registrar o ActivityResult para as permissões de localização adicionando este bloco de código a: // TODO: Step 5. Register ActivityResult to request Location permissions
val requestLocationPermissions = rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted -> if (isGranted) { viewModel.onPermissionChange(ACCESS_COARSE_LOCATION, isGranted) viewModel.onPermissionChange(ACCESS_FINE_LOCATION, isGranted) viewModel.fetchLocation() } else { coroutineScope.launch { snackbarHostState.showSnackbar("Location currently disabled due to denied permission.") } } }
Depois disso, vamos adicionar a caixa de diálogo de explicação das permissões de localização incluindo este bloco de código em: // TODO: Step 6. Add explanation dialog for Location permissions
var showExplanationDialogForLocationPermission by remember { mutableStateOf(false) } if (showExplanationDialogForLocationPermission) { LocationExplanationDialog( onConfirm = { // TODO: Step 10. Change location request to only request COARSE location. requestLocationPermissions.launch(arrayOf(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION)) showExplanationDialogForLocationPermission = false }, onDismiss = { showExplanationDialogForLocationPermission = false }, ) }
Agora, vamos verificar, explicar (se necessário) e solicitar as permissões de localização. Se a permissão for concedida, podemos buscar a localização e preencher o registro de fotos. Vamos adicionar este bloco de código em: // TODO: Step 7. Check, request, and explain Location permissions
when { state.hasLocationAccess -> viewModel.fetchLocation() ActivityCompat.shouldShowRequestPermissionRationale(context.getActivity(), ACCESS_COARSE_LOCATION) || ActivityCompat.shouldShowRequestPermissionRationale( context.getActivity(), ACCESS_FINE_LOCATION) -> showExplanationDialogForLocationPermission = true else -> requestLocationPermissions.launch(arrayOf(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION)) }
Pronto, concluímos a seção de permissões deste codelab. Tente redefinir o app e conferir os resultados.
Resumo de como melhoramos a experiência do usuário e os benefícios para seu app:
- Solicite permissões no contexto (quando os usuários estão interagindo com o recurso) em vez de imediatamente após a inicialização do app → Reduz a confusão e a desistência de usuários.
- Crie telas para explicar aos usuários por que nosso app precisa de acesso a permissões → Aumenta a transparência para os usuários.
- Use a API shouldShowRequestPermissionRationale() para determinar quando o sistema acredita que seu app deve mostrar uma tela de explicação → Aumenta as taxas de aceitação de permissão e diminui as chances de negação permanente de permissão.
5. Prática recomendada: reduzir o acesso do app à localização
A localização é uma das permissões mais sensíveis, e é por isso que ela aparece no Painel de privacidade do Android.
Resumindo, no Android 12, fornecemos aos usuários outros controles de localização. Os usuários agora têm uma escolha clara para compartilhar dados de local menos precisos com os apps, selecionando local aproximado em vez de local exato quando os apps solicitam acesso ao local.
O local aproximado fornece ao app uma estimativa da localização do usuário dentro de três quilômetros quadrados, o que deve ser uma precisão suficiente para muitos recursos do app. Recomendamos que todos os desenvolvedores com apps que precisam de acesso à localização revisem os casos de uso e só solicitem ACCESS_FINE_LOCATION
se o usuário estiver ativamente interagindo com um recurso que exija o local exato.
Gráfico para visualizar uma faixa estimada de localização aproximada no centro de Los Angeles, Califórnia.
O acesso ao local aproximado é o suficiente para nosso app PhotoLog, já que só precisamos da cidade do usuário para guardar a "recordação". No entanto, o app está solicitando ao usuário ACCESS_COARSE_LOCATION
e ACCESS_FINE_LOCATION
no momento. Vamos mudar isso.
Primeiro, precisamos editar o resultado da atividade para a localização e fornecer a função ActivityResultContracts.RequestPermission()
como um parâmetro em vez de ActivityResultContracts.RequestMultiplePermissions()
para refletir o fato de que só vamos solicitar ACCESS_COARSE_LOCATION
.
Vamos substituir o objeto requestLocationsPermissions atual (identificado por // TODO: Step 8. Change activity result to only request Coarse Location
) por este bloco de código:
val requestLocationPermissions = rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted -> if (isGranted) { viewModel.onPermissionChange(ACCESS_COARSE_LOCATION, isGranted) } }
Em seguida, vamos mudar os métodos launch()
para solicitar apenas ACCESS_COARSE_LOCATION
, em vez das duas permissões de localização.
Vamos substituir:
requestLocationPermissions.launch(arrayOf(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION))
... por:
requestLocationPermissions.launch(ACCESS_COARSE_LOCATION)
Há duas instâncias dos métodos launch()
no PhotoLog que vamos precisar mudar. Uma delas está na lógica onConfirm()
no LocationExplanationDialog
indicada por // TODO: Step 9. Change location request to only request COARSE location
. Outra está no item de lista "Location" indicado por // TODO: Step 10. Change location request to only request COARSE location
.
Por fim, agora que não estamos mais solicitando a permissão ACCESS_FINE_LOCATION
para o PhotoLog, vamos remover esta seção do método onPermissionChange() em AddLogViewModel.kt:
Manifest.permission.ACCESS_FINE_LOCATION -> { uiState = uiState.copy(hasLocationAccess = isGranted) }
Não se esqueça de remover também o ACCESS_FINE_LOCATION
do manifesto do app:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Agora concluímos a seção de localização do codelab. Desinstale/reinstale o app e confira os resultados.
6. Prática recomendada: minimizar o uso de permissões de armazenamento
É comum que os apps usem fotos armazenadas em um dispositivo. Para permitir que os usuários escolham imagens e vídeos, esses apps geralmente implementam os próprios seletores de arquivo, o que exige que os apps solicitem permissão para amplo acesso ao armazenamento. Os usuários não gostam de conceder acesso a todas as fotos, e os desenvolvedores não gostam de manter um seletor de arquivos independente.
O Android 13 introduz o seletor de fotos: uma ferramenta para fornecer ao usuário uma maneira de selecionar arquivos de mídia sem precisar conceder a um app acesso a toda a biblioteca de mídia. Ele também tem backport para o Android 11 e 12 com a ajuda das Atualizações do sistema do Google Play.
Para o recurso no app PhotoLog, vamos usar o ActivityResultContract PickMultipleVisualMedia
. Ele vai usar o seletor de fotos do Android quando presente no dispositivo e vai depender da intent ACTION_OPEN_DOCUMENT
em dispositivos mais antigos.
Primeiro, vamos registrar o ActivityResultContract no arquivo AddLogScreen
. Para fazer isso, adicione o bloco de código abaixo depois da linha: // TODO: Step 11. Register ActivityResult to launch the Photo Picker
val pickImage = rememberLauncherForActivityResult( PickMultipleVisualMedia(MAX_LOG_PHOTOS_LIMIT), viewModel::onPhotoPickerSelect )
Observação: o MAX_LOG_PHOTOS_LIMIT
mostrado aqui representa o limite máximo que definimos para quantas fotos podem ser adicionadas a um registro (neste caso, são três).
Agora, precisamos substituir o seletor interno que estava no app pelo seletor de fotos do Android. Adicione o código abaixo após o bloco: // TODO: Step 12. Replace the below line showing our internal UI by launching the Android Photo Picker instead
pickImage.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly))
Ao adicionar essas duas linhas de código, agora temos uma forma sem permissões de acessar as fotos do dispositivo que oferece uma UX muito melhor e não exige manutenção do código.
Como o PhotoLog não exige mais a grade de fotos legada e as permissões de armazenamento para acessar fotos, agora precisamos remover todo o código que contém a grade de fotos legada, desde a entrada de permissão de armazenamento no manifesto à lógica por trás dela, já que não é mais necessária no nosso app.
7. Recomendado: usar APIs de auditoria de acesso aos dados em builds de depuração
Você tem um app grande com muitos recursos e colaboradores (ou espera ter no futuro) que dificultam o rastreamento dos tipos de dados do usuário que o app acessa? Você sabia que, mesmo que os acessos aos dados venham de APIs ou SDKs que foram usados em algum momento, mas agora estão apenas persistindo no app, o app ainda é responsável pelo acesso?
Sabemos que é difícil acompanhar todos os locais onde seus apps acessam dados particulares, incluindo todos os SDKs incluídos e outras dependências. Para ajudar você a oferecer mais transparência sobre como o app e as dependências dele acessam dados particulares dos usuários, o Android 11 introduziu a auditoria de acesso a dados. Com essa API, os desenvolvedores podem realizar ações específicas, como mostrar um arquivo de registro, sempre que um destes eventos ocorrer:
- O código do seu app acessa dados particulares.
- O código em uma biblioteca dependente ou o SDK acessa dados particulares.
Primeiro, vamos conferir os conceitos básicos de como a API de auditoria de acesso a dados funciona no Android. Para adotar essa auditoria, vamos registrar uma instância de AppOpsManager.OnOpNotedCallback
(exige destinar ao Android 11 ou mais recente).
Também precisamos substituir os três métodos no callback, que vão ser invocados pelo sistema quando o app acessar dados do usuário de maneiras diferentes. São estes:
onNoted()
: chamado quando um app invoca APIs síncronas (vinculação bidirecional) que acessam dados do usuário. Normalmente, são chamadas de API que não exigem callback.onAsyncNoted()
: chamado quando um app invoca APIs assíncronas (vinculação unidirecional) que acessam dados do usuário. Normalmente, são chamadas de API que exigem callbacks, e o acesso aos dados ocorre quando o callback é invocado.onSelfNoted()
: bastante improvável, acontece quando um app transmite o próprio UID para noteOp(), por exemplo.
Agora vamos determinar qual desses métodos se aplica aos acessos aos dados do app PhotoLog. O PhotoLog acessa os dados do usuário principalmente em dois momentos: assim que ativamos a câmera e quando acessamos a localização do usuário. Ambas são chamadas de API assíncronas porque ambas dependem bastante de recursos. Esperamos que o sistema invoque onAsyncNoted()
ao acessar os respectivos dados do usuário.
Vamos aprender a adotar as APIs de auditoria de acesso a dados do PhotoLog.
Primeiro, precisamos criar uma instância de AppOpsManager.OnOpNotedCallback()
e substituir os três métodos acima.
Para os três métodos no objeto, vamos registrar a operação específica que acessou dados particulares do usuário. Essa operação contém mais informações sobre os tipos de dados do usuário que foram acessados. Além disso, como esperamos que onAsyncNoted()
seja chamado quando nosso app acessar as informações de localização e da câmera, vamos fazer algo especial e registrar um emoji de mapa para ter acesso à localização e um emoji de câmera para acesso à câmera. Para isso, podemos adicionar o bloco de código abaixo em: // TODO: Step 1. Create Data Access Audit Listener Object
@RequiresApi(Build.VERSION_CODES.R) object DataAccessAuditListener : AppOpsManager.OnOpNotedCallback() { // For the purposes of this codelab, we are just logging to console, // but you can also integrate other logging and reporting systems here to track // your app's private data access. override fun onNoted(op: SyncNotedAppOp) { Log.d("DataAccessAuditListener","Sync Private Data Accessed: ${op.op}") } override fun onSelfNoted(op: SyncNotedAppOp) { Log.d("DataAccessAuditListener","Self Private Data accessed: ${op.op}") } override fun onAsyncNoted(asyncNotedAppOp: AsyncNotedAppOp) { var emoji = when (asyncNotedAppOp.op) { OPSTR_COARSE_LOCATION -> "\uD83D\uDDFA" OPSTR_CAMERA -> "\uD83D\uDCF8" else -> "?" } Log.d("DataAccessAuditListener", "Async Private Data ($emoji) Accessed: ${asyncNotedAppOp.op}") } }
Em seguida, precisamos implementar a lógica de callback que acabamos de criar. Para ter resultados melhores, recomendamos fazer isso o mais rápido possível, porque o sistema só vai começar a rastrear o acesso aos dados depois de registrarmos o callback. Para registrar o callback, adicione o bloco de código abaixo em: // TODO: Step 2. Register Data Access Audit Callback
.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { val appOpsManager = getSystemService(AppOpsManager::class.java) as AppOpsManager appOpsManager.setOnOpNotedCallback(mainExecutor, DataAccessAuditListener) }
8. Conclusão
Vamos fazer um resumo do que aprendemos. Nós…
- Aprendemos por que a privacidade é importante para seus apps.
- Conhecemos os recursos de privacidade do Android.
- Implementamos várias práticas recomendadas de privacidade para apps, como:
- Solicitar permissões no contexto.
- Reduzir o acesso do app à localização.
- Usar o seletor de fotos e outras melhorias de armazenamento.
- Usar as APIs de auditoria de acesso a dados.
- Implementamos essas práticas recomendadas para melhorar a privacidade do app.
Esperamos que você tenha gostado da nossa jornada para melhorar a privacidade e a experiência do usuário do PhotoLog e tenha aprendido muitos conceitos ao longo do curso.
Para encontrar nosso código de referência (opcional):
Se ainda não tiver feito isso, confira o código da solução do codelab na pasta PhotoLog_End
. Se você tiver seguido as instruções deste codelab, o código na pasta PhotoLog_Start
vai ser idêntico ao usado na pasta PhotoLog_End
.
Saiba mais
Pronto! Para saber mais sobre as práticas recomendadas que abordamos acima, consulte a página de destino de privacidade do Android.