Desde o Android 6.0 Marshmallow, o Android usa um modelo de permissões que simplifica o processo de instalação de apps e atualização automática. As permissões são solicitadas durante a execução, e não antes da instalação do app. Além disso, os usuários podem optar por negar permissões específicas. Para oferecer essa flexibilidade aos usuários, verifique se o app se comporta como esperado quando um usuário ativa ou desativa uma permissão específica.
O Google Play Services tem permissões de execução que os usuários podem recusar separadamente das permissões solicitadas especificamente pelo aplicativo. O Google Play Services recebe automaticamente todas as permissões necessárias para oferecer suporte às APIs. No entanto, o app ainda precisa verificar e solicitar permissões de execução conforme necessário e processar erros adequadamente nos casos em que um usuário negou ao Google Play Services a permissão necessária para uma API usada pelo app.
Recomendamos gerenciar as expectativas do usuário ao definir as permissões necessárias para o ambiente de execução. As práticas recomendadas a seguir ajudarão você a evitar possíveis problemas.
Pré-requisitos
É necessário declarar as permissões no arquivo AndroidManifest.xml
.
Exemplo:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
Diretrizes
Verificar permissões antes de chamar APIs
Depois de declarar as APIs que você quer usar no
arquivo AndroidManifest.xml
, verifique se você tem a permissão necessária
antes de chamar uma API. Isso pode ser feito usando o método checkSelfPermission
de ActivityCompat
ou ContextCompat
.
Se a chamada retornar "false", isso significa que as permissões não foram concedidas, e você
precisará usar requestPermissions
para solicitá-las. A resposta é
retornada em um callback, que você verá na próxima etapa.
Exemplo:
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Check Permissions Now
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
REQUEST_LOCATION);
} else {
// permission has been granted, continue as usual
Task<Location> locationResult = LocationServices
.getFusedLocationProviderClient(this /** Context */)
.getLastLocation();
}
Implementar o callback de permissão de solicitação
Se a permissão necessária para o app não tiver sido concedida pelo usuário, o método
requestPermissions
precisará ser chamado para solicitar que o
usuário a conceda. A resposta do usuário é capturada no
callback onRequestPermissionsResult
. O app precisa
implementar isso e sempre verificar os valores de retorno, porque a solicitação pode ser
negada ou cancelada. Também é possível solicitar e verificar várias permissões de uma só vez. O exemplo a seguir verifica apenas uma permissão.
public void onRequestPermissionsResult(int requestCode,
String[] permissions,
int[] grantResults) {
if (requestCode == REQUEST_LOCATION) {
if(grantResults.length == 1
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// We can now safely use the API we requested access to
Task<Location> locationResult = LocationServices
.getFusedLocationProviderClient(this /** Context */)
.getLastLocation();
} else {
// Permission was denied or request was cancelled
}
}
}
Mostrar a lógica da permissão
Se as permissões solicitadas pelo app forem necessárias para os recursos principais do app e o usuário tiver negado a solicitação de permissão, o app precisará mostrar uma explicação adicional antes de solicitar a permissão novamente. É mais provável que os usuários concedam permissões quando entendem por que elas são necessárias e o benefício imediato para eles.
Nesse caso, antes de chamar requestPermissions
, chame
shouldShowRequestPermissionRationale
. Se ela retornar
"true", crie alguma interface para mostrar mais contexto da
permissão.
Por exemplo, seu código pode ficar assim:
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Check Permissions Now
private static final int REQUEST_LOCATION = 2;
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_FINE_LOCATION)) {
// Display UI and wait for user interaction
} else {
ActivityCompat.requestPermissions(
this, new String[]{Manifest.permission.LOCATION_FINE},
ACCESS_FINE_LOCATION);
}
} else {
// permission has been granted, continue as usual
Task<Location> locationResult = LocationServices
.getFusedLocationProviderClient(this /** Context */)
.getLastLocation();
}
Gerenciar falhas de conexão
Se o app usar o GoogleApiClient
descontinuado, quando você chamar
connect()
, o Google Play Services vai validar se ele tem todas as
permissões necessárias. A connect()
falha quando algum grupo de permissões
necessário para o Google Play Services está ausente.
Se a chamada para connect()
falhar, verifique se o app processa a
falha de conexão corretamente. Se o Google Play Services
não tiver permissões, você poderá invocar startResolutionForResult()
para
iniciar o fluxo do usuário para corrigi-las.
Exemplo:
@Override
public void onConnectionFailed(ConnectionResult result) {
if (mResolvingError) {
// Already attempting to resolve an error.
return;
} else if (result.hasResolution()) {
try {
mResolvingError = true;
result.startResolutionForResult(this, REQUEST_RESOLVE_ERROR);
} catch (SendIntentException e) {
// There was an error with the resolution intent. Try again.
mGoogleApiClient.connect();
}
} else {
// Show dialog using GooglePlayServicesUtil.getErrorDialog()
showErrorDialog(result.getErrorCode());
mResolvingError = true;
}
}
As chamadas de API mais recentes baseadas em GoogleApi
exibem automaticamente uma caixa de diálogo (se
o cliente for instanciado com um Activity
) ou uma notificação da bandeja do sistema (se
o cliente for instanciado com um Context
). O usuário poderá tocar para iniciar a
intent de resolução de permissões. As chamadas serão enfileiradas e repetidas quando a
permissão for concedida.