Desde o Android 6.0 Marshmallow, o Android usa um modelo de permissões, que simplifica a instalação do app e processo de atualização automática. As permissões são solicitadas no momento da execução e não antes instalação do app. Além disso, os usuários podem optar por negar permissões específicas. Para dar aos usuários essa flexibilidade, você precisa garantir que seu aplicativo se comporte da forma esperada 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 escolher negar separadamente das permissões solicitadas pelo para o aplicativo. O Google Play Services recebe automaticamente todas as permissões necessárias para dar suporte às APIs. No entanto, o app ainda vai precisar verificar e solicitar o ambiente de execução as permissões necessárias e lidar com os erros de forma adequada nos casos em que um usuário negou ao Google Play Services uma permissão necessária para uma API usada pelo seu app.
É uma boa prática gerenciar as expectativas do usuário ao definir permissões que o ambiente de execução pode exigir. As práticas recomendadas a seguir ajudarão você a evitar possíveis problemas.
Pré-requisitos
Você vai precisar declarar permissões no arquivo AndroidManifest.xml
.
Exemplo:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
Diretrizes
Verificar as permissões antes de chamar APIs
Depois de declarar as APIs que você quer usar no
AndroidManifest.xml
, verifique se você tem a permissão necessária
antes de chamar uma API. Para isso, use o método checkSelfPermission
.
de ActivityCompat
ou ContextCompat
.
Se a chamada retornar "false", as permissões não foram concedidas e você
precisa usar requestPermissions
para solicitá-las. A resposta para isso é
em um callback, que você vai conhecer 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
O método requestPermissions
deve ser chamado para solicitar
que o usuário conceda. A resposta do usuário é capturada no
Callback onRequestPermissionsResult
. Seu app precisa
implementá-la e sempre verificar os valores de retorno, pois a solicitação pode ser
negado ou cancelado. Você também pode solicitar e verificar várias permissões em
uma vez. O exemplo a seguir verifica apenas uma única 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 justificativa da permissão
Se as permissões solicitadas pelo aplicativo forem necessárias para os recursos principais do e o usuário negou a solicitação de permissão, o app deverá exibir uma explicação adicional antes de solicitar a permissão novamente. Usuários têm mais chances de conceder permissões quando entendem o motivo delas necessário e o benefício imediato para ele.
Nesse caso, antes de chamar requestPermissions
, chame
shouldShowRequestPermissionRationale
. Se ela retornar
verdadeiro, você deve criar alguma interface para exibir contexto adicional para o
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();
}
Lidar com falhas de conexão
Caso seu app use o GoogleApiClient
, que foi descontinuado, quando você chamar
connect()
, o Google Play Services vai validar que tem todos os
as permissões necessárias. A connect()
falha quando qualquer grupo de permissões
necessários para o próprio Google Play Services não estão.
Se a chamada para connect()
falhar, verifique se o app processa a
falha na conexão corretamente. Se o Google Play Services
não tiver permissões, invoque startResolutionForResult()
para
inicie o fluxo do usuário para corrigi-los.
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
exibirão automaticamente uma caixa de diálogo (se
o cliente é instanciado com um Activity
) ou notificação da bandeja do sistema (se
o cliente é instanciado com um Context
) que o usuário pode tocar para iniciar a
intent de resolução de permissões. As chamadas serão enfileiradas e repetidas depois que o
seja concedida.