Android KitKat securityException al intentar leer desde MediaStore

java.lang.SecurityException: denegación de permiso: proveedor de apertura com.android.providers.media.MediaDocumentsProvider de ProcessRecord {430b1748 29271: com.xxx/u0a88} (pid = 29271, uid = 10088) requiere android.permission.MANAGE_DOCUMENTS o android. permiso.MANAGE_DOCUMENTS

READ_EXTERNAL_STORAGE permisos MANAGE_DOCUMENTS y READ_EXTERNAL_STORAGE pero sigo recibiendo este error. El código ofensivo:

  public static String getImagePath(HailoDriverApplication app, Uri uri) { Cursor cursor = null; if (uri == null) { return null; } try { cursor = app.getContentResolver().query(uri, new String[] { MediaStore.Images.Media.DATA }, null, null, null); int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); if (cursor.moveToFirst()) { return cursor.getString(column_index); } } finally { if (cursor != null) { cursor.close(); } } return null; } 

Como fragmento solicitado de manifiesto:

                          

Tuve el mismo problema en los últimos días. Intenté algunas soluciones, pero por alguna razón recibí la denegación de permiso del proveedor de contenido de Uri para algunas imágenes incluso cuando tenía el permiso android.permission.MANAGE_DOCUMENTS agregado a mi manifiesto.

Aquí hay una solución alternativa, por el momento:

 i = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); startActivityForResult(i, CHOOSE_IMAGE); 

Esto fuerza la apertura de la galería de imágenes anterior en lugar de la nueva vista de documentos de Kitkat.

Ahora, puedes obtener el Uri llamando a lo siguiente en tu onActivityResult:

 Uri selectedImageURI = data.getData(); 

Espero que esto ayude.

En la intención utilizada para solicitar al usuario que agregue un archivo, use Intent.ACTION_OPEN_DOCUMENT (en KitKat API 19 o superior) en lugar de Intent.ACTION_GET_CONTENT o Intent.ACTION_PICK. Luego, cuando desee usar el Uri, tome los permisos persistentes anteriores establecidos por Intent.ACTION_OPEN_DOCUMENT como se describe en el enlace de @ feri ( https://developer.android.com/guide/topics/providers/document-provider.html #permissions ):

 final int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); // Check for the freshest data. getContentResolver().takePersistableUriPermission(originalUri, takeFlags); 

Puede leer más sobre las diferencias entre Intent.ACTION_GET_CONTENT, Intent.ACTION_PICK e Intent.ACTION_OPEN_DOCUMENT aquí: http://developer.android.com/reference/android/content/Intent.html#ACTION_OPEN_DOCUMENT

OK, encontré una muestra de trabajo que supera el problema:

  intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("image/*"); startActivityForResult(intent, myClassConstant.SELECT_PICTURE); 

Esto es lo que aprendí … este es un cambio en KitKat, y este código solo funciona en API 19 en adelante. No funcionará para versiones anteriores, por lo que también debe tener métodos para preKitKat. Una vez que obtenga el archivo usando el argumento Category_Openable, en mi caso una imagen, puede usarlo haciendo referencia a él como el URI. En mi caso, guardo el URIString (ruta del archivo) y puedo hacer lo que quiera con él después de que se abra.

El problema que estoy tratando de averiguar es cuánto tiempo los permisos de archivo persisten. Parece que expiró desde ayer, ya que mi código busca el UriString, luego intenta abrir el archivo. Si utilizo el código de arriba para seleccionar la imagen, funciona; almacena el nombre, y pude salir del progtwig, volver a entrar y aún así funcionó … sin embargo, mi primera ejecución del progtwig esta mañana (después sin tocarlo en más de 12 horas), actuó como si no pudiera encontrar el archivo (y estoy seguro de que si miro el depurador, vería que el error no crítico vuelve a aparecer).

Entonces, ahora la pregunta es: ¿Cómo persistimos los permisos una vez que sé cuál es el archivo (nombre)?

Supongo que el URI que desea mostrar hace referencia a una imagen de un proveedor que implementa el nuevo Storage Access Framework presentado con Android 4.4 KitKat. Puede ser Gallery o Google Drive. La única forma de acceder a estos documentos parece ser usar el selector de archivos del sistema. Si el usuario selecciona los archivos para abrir, el sistema concede permiso a la aplicación, que inició el diálogo Abrir archivo. Estos permisos son válidos siempre que el dispositivo no se reinicie. No se puede acceder a otras imágenes y dar lugar a la excepción de seguridad.

Si se persiste el URI, entonces los derechos concedidos para acceder al Uri también deben persistir. Para obtener más detalles, consulte aquí: https://developer.android.com/guide/topics/providers/document-provider.html#permissions

El permiso de MANAGE_DOCUMENTS puede ser retenido por el sistema:

El permiso MANAGE_DOCUMENTS. Por defecto, un proveedor está disponible para todos. Agregar este permiso restringe su proveedor al sistema. Esta restricción es importante para la seguridad.

(tomado de Storage Access Framework )

Entonces, al usar este permiso en su DocumentProvider , está restringiendo el acceso a su proveedor solo al sistema. Lo que esto significa es que solo el System UI picker del System UI picker podrá acceder a sus archivos. Por lo tanto, para que una aplicación pueda elegir un archivo de su Provider , deberá iniciar una Intent con ACTION_OPEN_DOCUMENT , que de hecho iniciará el System UI picker del System UI picker , el usuario elegirá un archivo de allí y luego el URI será devuelto a tú.

La solución parece estar usando http://developer.android.com/guide/topics/providers/document-provider.html#client para acceder a las imágenes de la galería

No estoy seguro de por qué el otro enfoque no funciona. Pero es una solución a corto plazo por ahora.