picture fileprovider android android-manifest android-contentprovider manifest-merging

fileprovider - android take picture programmatically



Posible utilizar mĂșltiples autoridades con FileProvider? (2)

Mi solución a este problema realmente ha sido evitar confiar en un único FileProvider analizando múltiples autoridades. Si bien esto no aborda directamente la pregunta como se indica, lo estoy publicando para la posteridad.

FileProvider mi biblioteca para aprovechar una subclase vacía de FileProvider , de modo que la entrada del proveedor de manifiesto actualizado de la biblioteca ahora es:

<provider android:name=".flow.email.screenshot.BugShakerFileProvider" android:authorities="${applicationId}.bugshaker.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/library_file_paths" /> </provider>

El manifiesto combinado de una aplicación que (1) utiliza un FileProvider archivo y (2) consume mi biblioteca ahora contendrá las dos entradas que se muestran a continuación (¡no hay colisión!):

<provider android:name="android.support.v4.content.FileProvider" android:authorities="com.consuming.application.fileprovider" android:exported="false" android:grantUriPermissions="true" > <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/application_file_paths" /> </provider> <provider android:name="com.github.stkent.bugshaker.flow.email.screenshot.BugShakerFileProvider" android:authorities="com.consuming.application.bugshaker.fileprovider" android:exported="false" android:grantUriPermissions="true" > <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/library_file_paths" /> </provider>

No me di cuenta de que esta era una solución potencial hasta que un compañero de trabajo lo señaló. Mi suposición había sido previamente (e incorrectamente) que todos los FileProvider s en el manifiesto deben establecer

android:name="android.support.v4.content.FileProvider"

Pero una revisión rápida de la documentación reveló mi error:

El nombre de la clase que implementa el proveedor de contenido, una subclase de ContentProvider. Este debe ser un nombre de clase completo (como "com.example.project.TransportationProvider"). [...]

Fondo

Mantengo una library cuya funcionalidad principal consiste en compartir capturas de pantalla capturadas mediante programación a aplicaciones de correo electrónico externas.

Utilizo un FileProvider para lograr esto, lo que significa que el manifiesto de mi biblioteca contiene una etiqueta <provider> :

<provider android:name="android.support.v4.content.FileProvider" android:authorities="${applicationId}.bugshaker.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths" /> </provider>

filepaths.xml se define de la siguiente manera:

<paths> <files-path path="bug-reports/" name="bug-reports" /> </paths>

Un consumidor de mi biblioteca tiene una aplicación que usa un FileProvider para compartir archivos. Mi expectativa era que debería ser posible permitir que ambos proveedores compartan archivos si la aplicación consumidora utiliza la siguiente etiqueta de manifiesto <provider> :

<provider android:authorities="${applicationId}.fileprovider;${applicationId}.bugshaker.fileprovider" android:exported="false" android:grantUriPermissions="true" android:name="android.support.v4.content.FileProvider" tools:replace="android:authorities"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" tools:replace="android:resource" /> </provider>

Esta entrada manifiesta:

  • especifica dos autoridades del Provider , ${applicationId}.fileprovider (para compartir archivos de la aplicación) y ${applicationId}.bugshaker.fileprovider (para compartir archivos de la biblioteca);
  • hace referencia a filepaths.xml actualizado, que contiene definiciones de directorios independientes para los archivos generados por la aplicación y los archivos generados por la biblioteca:

<paths> <external-path name="redacted" path="" /> <files-path name="bug-reports" path="bug-reports/" /> </paths>

Después de crear la aplicación, hemos confirmado que el manifiesto generado ha tenido los nodos correctos reemplazados con estos valores actualizados.

Sin embargo, cuando la aplicación que utiliza esta configuración se ensambla (correctamente) y se ejecuta, vemos un bloqueo en el inicio:

E: FATAL EXCEPTION: main Process: com.stkent.bugshakertest, PID: 11636 java.lang.RuntimeException: Unable to get provider android.support.v4.content.FileProvider: java.lang.NullPointerException: Attempt to invoke virtual method ''android.content.res.XmlResourceParser android.content.pm.PackageItemInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)'' on a null object reference at android.app.ActivityThread.installProvider(ActivityThread.java:5856) at android.app.ActivityThread.installContentProviders(ActivityThread.java:5445) at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5384) at android.app.ActivityThread.-wrap2(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1545) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6119) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) Caused by: java.lang.NullPointerException: Attempt to invoke virtual method ''android.content.res.XmlResourceParser android.content.pm.PackageItemInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)'' on a null object reference at android.support.v4.content.FileProvider.parsePathStrategy(FileProvider.java:583) at android.support.v4.content.FileProvider.getPathStrategy(FileProvider.java:557) at android.support.v4.content.FileProvider.attachInfo(FileProvider.java:375) at android.app.ActivityThread.installProvider(ActivityThread.java:5853) at android.app.ActivityThread.installContentProviders(ActivityThread.java:5445)  at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5384)  at android.app.ActivityThread.-wrap2(ActivityThread.java)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1545)  at android.os.Handler.dispatchMessage(Handler.java:102)  at android.os.Looper.loop(Looper.java:154)  at android.app.ActivityThread.main(ActivityThread.java:6119)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) 

Al usar el depurador, puedo ver que el método FileProvider.parsePathStrategy invoca PackageManager.resolveContentProvider con la cadena de autoridad "${applicationId}.fileprovider;${applicationId}.bugshaker.fileprovider" . resolveContentProvider devuelve un valor nulo, lo que lleva a este NPE.

Si llamo a resolveContentProvider manualmente mientras resolveContentProvider una pausa en esta instrucción y paso "${applicationId}.fileprovider" o "${applicationId}.bugshaker.fileprovider" , resolveContentProvider devuelve una instancia de ProviderInfo no nula (lo que parece ser la esperada resultado).

Esta diferencia me confunde porque la documentación del elemento <provider> indica que se admiten varias autoridades:

Una lista de una o más autoridades URI que identifican los datos ofrecidos por el proveedor de contenido. Se enumeran varias autoridades separando sus nombres con un punto y coma. Para evitar conflictos, los nombres de autoridad deben usar una convención de nomenclatura de estilo Java (como com.example.provider.cartoonprovider). Normalmente, es el nombre de la subclase ContentProvider que implementa el proveedor

No hay valor predeterminado. Al menos una autoridad debe ser especificada.

Preguntas

  • ¿Es posible que una sola aplicación exponga un FileProvider con múltiples autorizaciones y rutas de archivos?
    • Si es así, ¿qué necesito cambiar para que funcione?
    • Si no es así, ¿hay otras formas de configurar el uso compartido de archivos dentro de mi biblioteca que eviten conflictos como este?

Enlaces de apoyo


También me enfrento a este problema y utilizo este enfoque para resolverlo. al igual que tengo un selector de imágenes de biblioteca que utiliza el proveedor de archivos y también mi aplicación usa un proveedor de archivos cuando construyo mi aplicación.

mi archivo proporcionar es

<provider android:name="android.support.v4.content.FileProvider" android:authorities="org.contentarcadeapps.photoeditor.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"/> </provider>

cambiar esto a

<provider android:name="android.support.v4.content.FileProvider" android:authorities="org.contentarcadeapps.photoeditor.fileprovider" android:exported="false" android:grantUriPermissions="true" tools:replace="android:authorities"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" tools:replace="android:resource"/> </provider>