web-dev-qa-db-fra.com

FileProvider lève une exception sur GetUriForFile

J'ai suivi l'exemple de code sur le référence développeur Android sur FileProviders mais cela ne fonctionnera pas.

J'ai configuré le chemin files/exports/ Dans la définition du fournisseur de fichiers dans mon manifeste et les fichiers référencés existent sur ce chemin.

Dans mon manifeste:

<provider Android:name="Android.support.v4.content.FileProvider" Android:authorities="com.company.app.fileprovider" Android:exported="false" Android:grantUriPermissions="true">
    <meta-data Android:name="Android.support.FILE_PROVIDER_PATHS" Android:resource="@xml/file_paths" />
</provider>

Et dans xml/file_paths.xml

<?xml version="1.0" encoding="UTF-8" ?>
<paths xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <files-path name="exports" path="exports/"/>
</paths>

Ensuite, j'essaye d'obtenir le content-uri avec le code suivant:

Java.IO.File exportFile = 
    new Java.IO.File ("/data/data/com.company.app/files/exports/file.pdf"); 
Android.Net.Uri exportUri = 
    Android.Support.V4.Content.FileProvider.GetUriForFile (this, "com.company.app.fileprovider", exportFile);

Cependant, j'obtiens cette erreur:

Exception of type 'Java.Lang.NullPointerException' was thrown.
  at Android.Runtime.JNIEnv.CallStaticObjectMethod (IntPtr jclass, IntPtr jmethod, Android.Runtime.JValue[] parms) [0x00064] in /Users/builder/data/lanes/monodroid-mlion-monodroid-4.10.2-branch/4b53fbd0/source/monodroid/src/Mono.Android/src/Runtime/JNIEnv.g.cs:1160 
  at Android.Support.V4.Content.FileProvider.GetUriForFile (Android.Content.Context context, System.String authority, Java.IO.File file) [0x00000] in <filename unknown>:0 
  at com.company.App.ImageAndSubtitle.cloudStorageDidDownloadFile (System.Object sender, com.company.App.CloudStorageEventArgs args) [0x001f7] in /app_path/Screens/ImageAndSubtitle.cs:187 
  --- End of managed exception stack trace ---
Java.lang.NullPointerException
    at Android.support.v4.content.FileProvider.parsePathStrategy(FileProvider.Java:243)
    at Android.support.v4.content.FileProvider.getPathStrategy(FileProvider.Java:217)
    at Android.support.v4.content.FileProvider.getUriForFile(FileProvider.Java:130)
    at mono.Java.lang.RunnableImplementor.n_run(Native Method)
    at mono.Java.lang.RunnableImplementor.run(RunnableImplementor.Java:29)
    at Android.os.Handler.handleCallback(Handler.Java:615)
    at Android.os.Handler.dispatchMessage(Handler.Java:92)
    at Android.os.Looper.loop(Looper.Java:137)
    at Android.app.ActivityThread.main(ActivityThread.Java:4838)
    at Java.lang.reflect.Method.invokeNative(Native Method)
    at Java.lang.reflect.Method.invoke(Method.Java:511)
    at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:875)
    at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:642)
    at dalvik.system.NativeStart.main(Native Method)

Mise à jour

À partir du code source Android, je pourrais le rechercher dans la mesure où je sais maintenant que cette commande dans Android.support.v4.content.FileProvider.parsePathStrategy(FileProvider.Java:243) échouera et retournera null:

final ProviderInfo info = context.getPackageManager().resolveContentProvider(authority, PackageManager.GET_META_DATA);

Mais je ne sais pas pourquoi ...

24
codingFriend1

J'ai finalement trouvé un bon exemple de code sur la façon de créer ContentProviders et FileProviders sur https://github.com/commonsguy/cw-omnibus/tree/master/ContentProvider

L'erreur réelle dans mon code était que dans le fichier Manifest j'avais la balise provider à l'extérieur de la balise application, mais elle doit être à l'intérieur. Le manifeste doit ressembler à ceci:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android" Android:versionCode="1" Android:versionName="1.0" package="com.company.app">
<uses-sdk Android:minSdkVersion="13" />

<permission
    Android:name="com.company.app.fileprovider.READ"
    Android:description="@string/perm_read"
    Android:label="@string/perm_read_label"/>
<uses-permission Android:name="com.company.app.fileprovider.READ"/>

<application Android:label="MyApp">

    <provider 
    Android:name="Android.support.v4.content.FileProvider" 
    Android:authorities="com.company.app.fileprovider" 
    Android:exported="false" 
    Android:grantUriPermissions="true"
    Android:readPermission="com.company.app.fileprovider.READ">
                <meta-data 
                Android:name="Android.support.FILE_PROVIDER_PATHS" 
                Android:resource="@xml/file_paths" />
    </provider>

</application>
<uses-permission Android:name="Android.permission.INTERNET" />

</manifest>
35
codingFriend1

En essayant de configurer un FileProvider pour obtenir un fichier PDF qui se trouve sur l'appareil et pouvoir l'envoyer par e-mail, j'ai également rencontré cette exception. En lisant les différentes réponses - il semble un peu compliqué de configurer correctement le FileProvider à la main (au moins cette première fois).

Enfin, ce qui a fonctionné pour moi a été de copier les composants de cet exemple dans un nouveau projet vide: https://github.com/IanDarwin/Android-Cookbook-Examples/tree/master/PdfShare

Une fois que je le vois fonctionner de manière autonome, je peux apporter les modifications à mon projet actuel.

Plus précisément, voici les fichiers à répliquer:

1. AndroidManifest.xml - où se trouve toute la configuration FileProvider délicate

2. file_paths.xml - Il s'agit d'un petit mais important composant. En regardant SO il y a une variété de réponses pour ce qu'il faut y mettre, mais c'est seulement à partir de ce projet que l'installation a fonctionné pour moi

3. MainActivity.Java - la configuration Java correspondante pour fonctionner avec ce qui est configuré dans le manifeste; et bien sûr, n'oubliez pas le fichier de mise en page associé

8
Gene Bo

Cette erreur s'est produite dans mon cas car j'avais transmis un nom de package incorrect au deuxième paramètre de GetUriForFile. J'ai utilisé BuildConfig.PACKAGE_NAME qui s'est résolu en Android.support.multidex qui est incorrect.

1
RasenKoD