Permisos en Xamarin.Android

Información general

Las aplicaciones Android se ejecutan en su propio espacio aislado y por motivos de seguridad no tienen acceso a determinados recursos del sistema o hardware en el dispositivo. El usuario debe conceder explícitamente permiso a la aplicación para poder usar estos recursos. Por ejemplo, una aplicación no puede acceder al GPS en un dispositivo sin permiso explícito del usuario. Android iniciará un Java.Lang.SecurityException si una aplicación intenta acceder a un recurso protegido sin permiso.

El desarrollador de aplicaciones declara los permisos en la AndroidManifest.xml cuando se desarrolla la aplicación. Android tiene dos flujos de trabajo diferentes para obtener el consentimiento del usuario para esos permisos:

  • En el caso de las aplicaciones destinadas a Android 5.1 (nivel de API 22) o inferior, la solicitud de permiso se produjo cuando se instaló la aplicación. Si el usuario no concedió los permisos, la aplicación no se instalaría. Una vez instalada la aplicación, no hay forma de revocar los permisos, excepto desinstalando la aplicación.
  • A partir de Android 6.0 (nivel de API 23), a los usuarios se les dio más control sobre los permisos; pueden conceder o revocar permisos siempre que la aplicación esté instalada en el dispositivo. En esta captura de pantalla se muestra la configuración de permisos de la aplicación Contactos de Google. Enumera los distintos permisos y permite al usuario habilitar o deshabilitar permisos:

Sample Permissions screen

Las aplicaciones Android deben comprobar en tiempo de ejecución para ver si tienen permiso para acceder a un recurso protegido. Si la aplicación no tiene permiso, debe realizar solicitudes mediante las nuevas API proporcionadas por Android SDK para que el usuario conceda los permisos. Los permisos se dividen en dos categorías:

  • Permisos normales – Estos son permisos que suponen un riesgo de seguridad menor para la seguridad o privacidad del usuario. Android 6.0 concederá automáticamente permisos normales en el momento de la instalación. Consulte la documentación de Android para obtener una Lista completa de permisos normales.
  • Permisos peligrosos: a diferencia de los permisos normales, los permisos peligrosos son aquellos que protegen la seguridad o privacidad del usuario. El usuario debe concederlos explícitamente. Enviar o recibir un mensaje SMS es un ejemplo de una acción que requiere un permiso peligroso.

Importante

La categoría a la que pertenece un permiso puede cambiar con el tiempo. Es posible que un permiso que se clasifique como un permiso "normal" se pueda elevar en niveles de API futuros a un permiso peligroso.

Los permisos peligrosos se dividen en grupos de permisos. Un grupo de permisos contendrá permisos relacionados lógicamente. Cuando el usuario concede permiso a un miembro de un grupo de permisos, Android concede automáticamente permiso a todos los miembros de ese grupo. Por ejemplo, el STORAGEgrupo de permisos contiene los permisos los WRITE_EXTERNAL_STORAGE permisos yREAD_EXTERNAL_STORAGE. Si el usuario concede permiso a READ_EXTERNAL_STORAGE, el WRITE_EXTERNAL_STORAGE permiso se concede automáticamente al mismo tiempo.

Antes de solicitar uno o varios permisos, es un procedimiento recomendado proporcionar una justificación sobre por qué la aplicación requiere el permiso antes de solicitar el permiso. Una vez que el usuario entiende la justificación, la aplicación puede solicitar permiso del usuario. Al reconocer la razón, el usuario puede tomar una decisión informada si desea conceder el permiso y comprender las repercusiones si no lo hacen.

Todo el flujo de trabajo de comprobación y solicitud de permisos se conoce como un permisos en tiempo de ejecución comprobación y se puede resumir en el diagrama siguiente:

Run-time permission check flow chart

La biblioteca de soporte técnico de Android devuelve algunas de las nuevas API para permisos a versiones anteriores de Android. Estas API respaldadas comprobarán automáticamente la versión de Android en el dispositivo, por lo que no es necesario realizar una comprobación del nivel de API cada vez.

En este documento se describe cómo agregar permisos a una aplicación de Xamarin.Android y cómo las aplicaciones destinadas a Android 6.0 (nivel de API 23) o superior deben realizar una comprobación de permisos en tiempo de ejecución.

Nota:

Es posible que los permisos de hardware afecten a la forma en que Google Play filtra la aplicación. Por ejemplo, si la aplicación requiere permiso para la cámara, Google Play no mostrará la aplicación en Google Play Store en un dispositivo que no tenga instalada una cámara.

Requisitos

Se recomienda encarecidamente que los proyectos de Xamarin.Android incluyan el paquete NuGet Xamarin.Android.Support.Compat. Este paquete volverá a importar las API específicas del permiso a versiones anteriores de Android, lo que proporciona una interfaz común sin necesidad de comprobar constantemente la versión de Android en la que se ejecuta la aplicación.

Solicitud de permisos del sistema

El primer paso para trabajar con permisos de Android es declarar los permisos en el archivo de manifiesto de Android. Esto debe hacerse independientemente del nivel de API que la aplicación tenga como destino.

Las aplicaciones que tienen como destino Android 6.0 o posterior no pueden suponer que, dado que el usuario concedió permiso en algún momento anterior, ese permiso será válido la próxima vez. Una aplicación destinada a Android 6.0 siempre debe realizar una comprobación de permisos en tiempo de ejecución. Las aplicaciones destinadas a Android 5.1 o versiones inferiores no necesitan realizar una comprobación de permisos en tiempo de ejecución.

Nota:

Las aplicaciones solo deben solicitar los permisos que requieren.

Declarar permisos en el manifiesto

Los permisos se agregan al AndroidManifest.xml con el elemento uses-permission. Por ejemplo, si una aplicación es buscar la posición del dispositivo, requiere permisos de ubicación de curso y finos. Los dos elementos siguientes se agregan al manifiesto:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

Es posible declarar los permisos mediante la compatibilidad con la herramienta integrada en Visual Studio:

  1. Haga doble clic en Propiedades en el Explorador de soluciones y seleccione la pestaña Manifiesto de Android en la ventana Propiedades:

    Required permissions in the Android Manifest tab

  2. Si la aplicación aún no tiene una AndroidManifest.xml, haga clic en No AndroidManifest.xml encontrado. Haga clic para agregar uno como se muestra a continuación:

    No AndroidManifest.xml message

  3. Seleccione los permisos que necesite la aplicación en la lista de Permisos necesarios y guarde:

    Example CAMERA permissions selected

Xamarin.Android agregará automáticamente algunos permisos en tiempo de compilación a las compilaciones de depuración. Esto facilitará la depuración de la aplicación. En concreto, dos permisos importantes son INTERNET y READ_EXTERNAL_STORAGE. Estos permisos establecidos automáticamente no aparecerán habilitados en la lista de Permisos necesarios. Sin embargo, las compilaciones de versión solo usan los permisos que se establecen explícitamente en la lista de Permisos necesarios .

En el caso de las aplicaciones que tienen como destino Android 5.1 (nivel de API 22) o inferior, no hay nada más que debe realizarse. Las aplicaciones que se ejecutarán en Android 6.0 (API 23 nivel 23) o posterior deben continuar con la sección siguiente sobre cómo realizar comprobaciones de permisos en tiempo de ejecución.

Comprobaciones de permisos en tiempo de ejecución en Android 6.0

El ContextCompat.CheckSelfPermissionmétodo (disponible con la biblioteca de soporte técnico de Android) se usa para comprobar si se ha concedido un permiso específico. Este método devolverá una Android.Content.PM.Permission enumeración que tiene uno de los dos valores:

  • Permission.Granted: se ha concedido el permiso especificado.
  • Permission.Denied: no se ha concedido el permiso especificado.

Este fragmento de código es un ejemplo de cómo comprobar el permiso Cámara en una actividad:

if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.Camera) == (int)Permission.Granted) 
{
    // We have permission, go ahead and use the camera.
} 
else 
{
    // Camera permission is not granted. If necessary display rationale & request.
}

Es un procedimiento recomendado informar al usuario sobre por qué es necesario un permiso para una aplicación para que se pueda tomar una decisión informada para conceder el permiso. Un ejemplo de esto sería una aplicación que toma fotos y etiquetas geográficas. Es claro para el usuario que el permiso de cámara es necesario, pero es posible que no esté claro por qué la aplicación también necesita la ubicación del dispositivo. La justificación debe mostrar un mensaje para ayudar al usuario a comprender por qué es deseable el permiso de ubicación y que se requiere el permiso de cámara.

El ActivityCompat.ShouldShowRequestPermissionRationale método se usa para determinar si se debe mostrar la justificación al usuario. Este método devolverá true si se debe mostrar la justificación de un permiso determinado. En esta captura de pantalla se muestra un ejemplo de una barra de aperitivos que muestra una aplicación que explica por qué la aplicación debe conocer la ubicación del dispositivo:

Rationale for location

Si el usuario concede el permiso, se debe llamar al ActivityCompat.RequestPermissions(Activity activity, string[] permissions, int requestCode) método. Este método requiere los parámetros siguientes:

  • actividad : esta es la actividad que solicita los permisos y que Android informa de los resultados.
  • permisos : una lista de los permisos que se solicitan.
  • requestCode : valor entero que se usa para hacer coincidir los resultados de la solicitud de permiso a una RequestPermissions llamada. Este valor debería ser mayor que cero.

Este fragmento de código es un ejemplo de los dos métodos que se trataron. En primer lugar, se realiza una comprobación para determinar si se debe mostrar la justificación del permiso. Si se va a mostrar la justificación, se muestra una barra de aperitivos con la justificación. Si el usuario hace clic Aceptar en la barra de aperitivos, la aplicación solicitará los permisos. Si el usuario no acepta la justificación, la aplicación no debe continuar con la solicitud de permisos. Si no se muestra la justificación, la Actividad solicitará el permiso:

if (ActivityCompat.ShouldShowRequestPermissionRationale(this, Manifest.Permission.AccessFineLocation)) 
{
    // Provide an additional rationale to the user if the permission was not granted
    // and the user would benefit from additional context for the use of the permission.
    // For example if the user has previously denied the permission.
    Log.Info(TAG, "Displaying camera permission rationale to provide additional context.");

    var requiredPermissions = new String[] { Manifest.Permission.AccessFineLocation };
    Snackbar.Make(layout, 
                   Resource.String.permission_location_rationale,
                   Snackbar.LengthIndefinite)
            .SetAction(Resource.String.ok, 
                       new Action<View>(delegate(View obj) {
                           ActivityCompat.RequestPermissions(this, requiredPermissions, REQUEST_LOCATION);
                       }    
            )
    ).Show();
}
else 
{
    ActivityCompat.RequestPermissions(this, new String[] { Manifest.Permission.Camera }, REQUEST_LOCATION);
}

RequestPermission se puede llamar incluso si el usuario ya ha concedido permiso. Las llamadas posteriores no son necesarias, pero proporcionan al usuario la oportunidad de confirmar (o revocar) el permiso. Cuando RequestPermission se llama a, el control se entrega al sistema operativo, que mostrará una interfaz de usuario para aceptar los permisos:

Permssion Dialog

Una vez finalizado el usuario, Android devolverá los resultados a la Actividad a través de un método de devolución de llamada, OnRequestPermissionResult. Este método forma parte de la interfaz ActivityCompat.IOnRequestPermissionsResultCallback que debe implementar la Actividad. Esta interfaz tiene un único método,OnRequestPermissionsResult, que Android invocará para informar a la actividad de las opciones del usuario. Si el usuario ha concedido el permiso, la aplicación puede seguir adelante y usar el recurso protegido. A continuación se muestra un ejemplo de cómo implementar OnRequestPermissionResult :

public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
    if (requestCode == REQUEST_LOCATION) 
    {
        // Received permission result for camera permission.
        Log.Info(TAG, "Received response for Location permission request.");

        // Check if the only required permission has been granted
        if ((grantResults.Length == 1) && (grantResults[0] == Permission.Granted)) {
            // Location permission has been granted, okay to retrieve the location of the device.
            Log.Info(TAG, "Location permission has now been granted.");
            Snackbar.Make(layout, Resource.String.permission_available_camera, Snackbar.LengthShort).Show();            
        } 
        else 
        {
            Log.Info(TAG, "Location permission was NOT granted.");
            Snackbar.Make(layout, Resource.String.permissions_not_granted, Snackbar.LengthShort).Show();
        }
    } 
    else 
    {
        base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}

Resumen

En esta guía se explica cómo agregar y comprobar los permisos en un dispositivo Android. Las diferencias en cómo funcionan los permisos entre las aplicaciones Android antiguas (nivel de API < 23) y las nuevas aplicaciones de Android (nivel de API > 22). Se ha explicado cómo realizar comprobaciones de permisos en tiempo de ejecución en Android 6.0.