móviles - manual de programacion android pdf
Permisos personalizados de Android-Marshmallow (5)
Fondo
Históricamente, los permisos personalizados de Android han sido un desastre y dependían del orden de instalación , lo que se sabe que expone vulnerabilidades .
Antes de la API 21, había una solución de solución perturbadora por la cual se declaraba el permiso personalizado de otra aplicación en su Manifiesto, se le otorgaba el permiso ... Sin embargo, desde la API 21, solo una aplicación puede declarar un permiso personalizado y la instalación de otra aplicación declarando Este mismo permiso, será prevenido.
Las alternativas son reinstalar la aplicación que requiere el permiso, de modo que el sistema las detecte, pero no es una buena experiencia para el usuario . O compruebe en tiempo de ejecución los permisos de la aplicación que realiza la llamada, pero eso no deja de tener sus defectos teóricos .
Problema
A partir de Android Marshmallow (6.0 - API 23), una aplicación necesita solicitar permiso del usuario para usar su propio permiso personalizado . Un permiso personalizado declarado no se concede automáticamente.
Esto parece peculiar, dado que solo una aplicación puede ahora declararlo.
Para replicar
Declare el permiso personalizado y un BroadcastReceiver en el Manifiesto.
<permission
android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"
android:description="@string/control_description"
android:icon="@mipmap/ic_launcher"
android:label="@string/control_label"
android:protectionLevel="normal or dangerous"/>
<uses-permission
android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"/>
// etc
<receiver
android:name="com.example.app.MyBroadcastReceiver"
android:permission="com.example.app.permission.CONTROL_EXAMPLE_APP">
<intent-filter android:priority="999">
<action android:name="com.example.app.REQUEST_RECEIVER"/>
</intent-filter>
</receiver>
Desde una aplicación de terceros, declare que usa el permiso personalizado en el Manifiesto (y acéptelo a través de un cuadro de diálogo o la configuración) y llame:
final Intent intent = new Intent("com.example.app.REQUEST_RECEIVER");
context.sendOrderedBroadcast(intent, "com.example.app.permission.CONTROL_EXAMPLE_APP", new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
// getResultCode();
}
}, null, Activity.RESULT_CANCELED, null, null);
El resultado devolverá CANCELADO y el registro mostrará:
system_process W / BroadcastQueue: denegación de permiso: recibir intento {act = com.example.app.REQUEST_RECEIVER flg = 0x10 (tiene extras)} a com.example.app/.MyBroadcastReceiver requiere com.example.app.permission.CONTROL_EXAMPLE_APP debido al remitente com.example.thirdparty
Si utilizo el cuadro de diálogo ActivityCompat.requestPermissions()
estándar para permitir que el usuario acepte el permiso, el receptor, como es de esperar, funciona correctamente.
Pregunta
¿Es este el comportamiento esperado? ¿O de alguna manera he pasado por alto algo?
Parecería ridículo plantear un diálogo diciendo
La aplicación Ejemplo de aplicación quiere permiso para usar la Aplicación de ejemplo
Y, de hecho, puede afectar al usuario, proporcionándole una solicitud tan absurda.
Por supuesto, puedo cambiar la descripción y el nombre del permiso, a algo que ellos aceptarían, como " comunicarse con otras aplicaciones instaladas ", pero antes de suspirar y tomar ese enfoque, pensé que iba a hacer esta pregunta.
Nota
El ejemplo de la transmisión ordenada es replicar el problema. Mi aplicación utiliza otras implementaciones de proveedores de contenido y un servicio vinculado. No es una implementación alternativa que requiera, es la confirmación del problema.
Gracias por leer hasta aquí.
Edición: Para aclarar, para otras implementaciones, como declarar un permiso en un Servicio (que sería más fácil de replicar), el permiso personalizado declarado se otorga automáticamente.
Como entendí, intentaste hacer lo siguiente (al menos, así fue como pude reproducir tu problema):
Usted declara su nuevo permiso personalizado en la primera aplicación (llamémosla F)
<permission android:name="com.example.app.permission.CONTROL_EXAMPLE_APP" android:description="@string/control_description" android:icon="@mipmap/ic_launcher" android:label="@string/control_label" android:protectionLevel="normal or dangerous"/>
Usted define que su aplicación F usa el permiso
com.example.app.permission.CONTROL_EXAMPLE_APP
. Eso es correcto como dice la directriz.<uses-permission android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"/>
Usted declara su receptor de difusión personalizado en su aplicación F. Para comunicarse con esa transmisión de su aplicación (no importa cuál, F u otra aplicación) debe obtener su permiso personalizado
<receiver android:name="com.example.app.MyBroadcastReceiver" android:permission="com.example.app.permission.CONTROL_EXAMPLE_APP"> <intent-filter android:priority="999"> <action android:name="com.example.app.REQUEST_RECEIVER"/> </intent-filter> </receiver>
Usted define que su segunda aplicación (vamos a llamarlo S) utiliza el permiso
com.example.app.permission.CONTROL_EXAMPLE_APP
. Porque desea permitir que la aplicación S envíe mensajes de difusión al receptor de la aplicación F.<uses-permission android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"/>
Finalmente, intenta enviar mensajes de difusión desde su aplicación S utilizando este código.
final Intent intent = new Intent("com.example.app.REQUEST_RECEIVER"); context.sendOrderedBroadcast(intent, "com.example.app.permission.CONTROL_EXAMPLE_APP", new BroadcastReceiver() { @Override public void onReceive(final Context context, final Intent intent) { // getResultCode(); } }, null, Activity.RESULT_CANCELED, null, null);
Y, esto es importante , otorgó permiso a su aplicación S, pero no le otorgó permiso a su aplicación F.
Como resultado, su receptor de difusión declarado en la aplicación F no recibió nada.
Después de otorgarle permiso a su aplicación F (tenga en cuenta que ahora S y F le otorgaron su permiso personalizado) todo funciona bien. El receptor de difusión declarado en la aplicación F recibió el mensaje de la aplicación S.
Supongo que es un comportamiento correcto, porque este doc nos dice:
Tenga en cuenta que, en este ejemplo, el permiso DEBIT_ACCT no solo se declara con el elemento, sino que también se solicita su uso con el elemento. Debe solicitar su uso para que otros componentes de la aplicación inicien la actividad protegida, aunque la protección la impone la propia aplicación.
Y la aplicación que declara permiso también debe solicitar el mismo permiso para comunicarse con sí misma.
Como resultado, la API 23 de Android debe obtener acceso para utilizar primero el usuario del formulario de permiso. Y debemos obtener 2 permisos otorgados, primero desde la aplicación F (porque guidline lo dice así) y segundo desde la aplicación S (porque solo necesitamos obtener acceso).
Pero no entendí tu siguiente punto:
Parecería ridículo plantear un diálogo diciendo
La Aplicación de ejemplo de la aplicación desea permiso para usar la Aplicación de ejemplo
Mi API nativa de Android 23 me muestra algo así:
La aplicación Ejemplo de aplicación quiere
Creo que el problema en su ejemplo es que requiere explícitamente que a ambas aplicaciones se les otorgue el permiso personalizado.
Esta parte requiere que la aplicación com.example.thirdparty tenga el permiso:
<receiver
android:name="com.example.app.MyBroadcastReceiver"
android:permission="com.example.app.permission.CONTROL_EXAMPLE_APP">
Y esta parte requiere que la aplicación com.example.app tenga el permiso también:
context.sendOrderedBroadcast(intent, "com.example.app.permission.CONTROL_EXAMPLE_APP", ...
Menciona que no tiene este problema cuando usa un servicio. No sé exactamente cómo usa el servicio, pero si simplemente lo declara así:
<service
android:name="com.example.app.MyService"
android:permission="com.example.app.permission.CONTROL_EXAMPLE_APP">
y luego atarlo de esta manera:
context.bindService(serviceIntent, mServiceConnection, ...
entonces es suficiente si com.example.thirdparty tiene el permiso otorgado, mientras que com.example.app no necesita tenerlo.
En otras palabras, creo que este comportamiento es por diseño, y la diferencia que ve entre el comportamiento de difusión y servicio se debe a que en el caso de difusión, solicita específicamente que com.example.app tenga el permiso personalizado, mientras que en el caso del servicio, no lo hagas
Espero no haber entendido mal tu problema. Si lo hice, hágamelo saber y eliminaré esta respuesta.
No creo que sea completamente cierto que un permiso personalizado declarado no se otorgue automáticamente a la aplicación. Para cuando el permiso personalizado tiene el nivel de protección "normal" o "firma", el permiso se otorga en el momento de la instalación. De lo contrario, si el nivel de protección es "peligroso", entonces es un permiso de tiempo de ejecución y funciona igual que otros permisos peligrosos: deberá solicitar al usuario que otorgue el permiso a la aplicación.
Primero agregue permisos en el archivo de manifiesto después de
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Si bien puede ser ambiguo para el usuario ver una solicitud de permiso para la aplicación que se declara en la misma aplicación, es la forma en que Android está diseñado para ejecutarse desde el malvavisco. Creo que, en la perspectiva de Android, el comportamiento es el previsto y correcto.