A partir de Android 6.0 Marshmallow, modelo de permisos que optimiza la instalación y de actualización automática. Los permisos se solicitan durante el tiempo de ejecución, no antes. instalación de la app. Además, los usuarios pueden rechazar permisos específicos. Para brindarles a los usuarios esta flexibilidad, debes asegurarte de que tu app se comporte de se espera cuando un usuario habilita o inhabilita un permiso específico.
Los Servicios de Google Play tienen permisos de tiempo de ejecución que los usuarios pueden elegir rechazar por separado de los permisos solicitados específicamente por su y mantener la integridad de su aplicación. Servicios de Google Play obtiene automáticamente todos los permisos que necesita para admitir sus APIs. Sin embargo, tu app debe verificar y solicitar el tiempo de ejecución permisos según sea necesario y manejar adecuadamente los errores en los casos en que un usuario rechazó a los Servicios de Google Play un permiso necesario para una API que usa tu app.
Es una buena práctica administrar las expectativas del usuario al establecer permisos que que puede requerir el entorno de ejecución. Las siguientes prácticas recomendadas te ayudarán a evitar posibles problemas.
Requisitos previos
Deberás declarar los permisos en tu archivo AndroidManifest.xml
.
Por ejemplo:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
Lineamientos
Verifica los permisos antes de llamar a las APIs
Una vez que hayas declarado las APIs que quieres usar en tu
AndroidManifest.xml
, asegúrate de tener el permiso necesario
antes de llamar a una API. Esto se puede hacer con el método checkSelfPermission
.
de ActivityCompat
o ContextCompat
.
Si la llamada muestra el valor "false", significa que no se otorgaron los permisos
debes usar requestPermissions
para solicitarlas. La respuesta a esto es
en una devolución de llamada que verás en el siguiente paso.
Por ejemplo:
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();
}
Cómo implementar la devolución de llamada de solicitud de permiso
Si el usuario no otorgó el permiso que necesita tu aplicación, el
Debes llamar al método requestPermissions
para preguntarle a la
usuario los otorgue. La respuesta del usuario se captura en el
Devolución de llamada onRequestPermissionsResult
. Tu app debe
implementar esto y siempre comprobar los valores que se devuelven, ya que la solicitud podría
rechazadas o canceladas. También puedes solicitar y verificar varios permisos en
una vez, el siguiente ejemplo solo verifica un único permiso.
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
}
}
}
Muestra la justificación del permiso
Si los permisos que solicita tu aplicación son necesarios para las funciones principales de la app y el usuario rechazó la solicitud de permiso anteriormente, tu app debe mostrar una explicación adicional antes de volver a solicitar el permiso. Usuarios tienen más probabilidades de otorgar permisos cuando comprenden el motivo del permiso y el beneficio inmediato para ellos.
En este caso, antes del requestPermissions
que realiza la llamada, debes llamar
shouldShowRequestPermissionRationale
Si devuelve
true, debes crear alguna IU para mostrar contexto adicional para el
permiso.
Por ejemplo, tu código podría verse de la siguiente manera:
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();
}
Soluciona las fallas de conexión
Si tu app usa el elemento GoogleApiClient
obsoleto, cuando llames
connect()
, Servicios de Google Play valida que cuente con todos los elementos
los permisos necesarios. connect()
falla cuando algún grupo de permisos
de los servicios de Google Play.
Si la llamada a connect()
falla, asegúrate de que tu app controle
error de conexión correctamente. Si los Servicios de Google Play
no tiene permisos, puedes invocar a startResolutionForResult()
para
iniciar el flujo del usuario para solucionarlos.
Por ejemplo:
@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;
}
}
Las llamadas a la API más nuevas basadas en GoogleApi
mostrarán automáticamente un diálogo (si
se crea una instancia del cliente con una Activity
) o con una notificación de la bandeja del sistema (si
se crea una instancia del cliente con un Context
) que el usuario puede presionar para iniciar
de resolución de permisos. Las llamadas se pondrán en cola y se reintentarán cuando
permiso.