FileProvider在获取文件URI时抛出异常

26

我按照Android开发者关于FileProviders的参考文献上的示例代码进行了操作,但它不起作用。

我在清单文件中的文件提供程序定义中设置了路径files/exports/,并且所引用的文件确实存在于该路径下。

我的清单文件内容如下:

<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>

并且在 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>

然后我尝试使用以下代码获取内容URI:

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);

但是我遇到了这个错误:

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)

更新

通过查看Android源代码,我发现在android.support.v4.content.FileProvider.parsePathStrategy(FileProvider.java:243)命令中会失败并返回null

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

但是我不知道为什么...

3个回答

38

我最终在https://github.com/commonsguy/cw-omnibus/tree/master/ContentProvider找到了一个很好的示例代码,用于创建ContentProviders和FileProviders。

我的代码实际上出错了,在清单文件中我把provider标签放在了application标签外面,而它必须在里面。清单文件必须像这样:

<?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>

谢谢你指出这个问题。这是一个愚蠢的错误。有时我的大脑会表现得很奇怪,我在做其他事情时会看到一些东西。 - Monish Kamble
3
这真是珍贵的发现,我之前没注意到,感谢你指出来。 - Flo We
3
救了我的一天。同时,file_paths.xml 中的 <root-path name="root" path="." /> 对我来说是必需的。 - Anatoly Vasilyev
这是一个部分答案。请通过添加Java端代码(用于从您的Activity或Fragment与此XML交互)来完成它。 - Abhinav Saxena
@Manoj 这可能是一个重复的问题。在 SOW 上不鼓励这样做。 - Abhinav Saxena
显示剩余2条评论

10
试图为从设备获取PDF文件并能够通过电子邮件发送而设置FileProvider时,我也遇到了这个异常。阅读各种答案后,手动正确设置FileProvider似乎有点复杂(至少第一次)。
最终对我有效的是将此示例中的组件复制到一个空的新项目中:https://github.com/IanDarwin/Android-Cookbook-Examples/tree/master/PdfShare 一旦我在独立环境中看到它正常工作,那么我就可以将更改引入我的实际项目中。
具体来说,这里是要复制的文件:
1. AndroidManifest.xml - 所有棘手的FileProvider配置都在这里

2. file_paths.xml - 这是一个小但重要的组件。在stackoverflow上有各种不同的答案,关于应该放什么内容,但只有从这个项目中才能让我正常工作。

3. MainActivity.java - 对应于在清单文件中配置的内容进行工作的Java设置;当然不要忘记相关的布局文件


我也看到了很多答案,但这个编译集是我找到的最接近的一组。我不得不进行一些小调整,以适应Xamarin.Android。谢谢! - OliveJuice

1
这个错误发生在我身上,因为我将错误的包名传递给了 GetUriForFile 的第二个参数。我使用了 BuildConfig.PACKAGE_NAME,它解析为 android.support.multidex,这是错误的。

1
这并没有回答问题。一旦您拥有足够的声望,您将能够评论任何帖子;相反,提供不需要询问者澄清的答案。- 来自审核 - the8472
3
这只是另一个错误,导致相同的异常。 - RasenKoD
1
我第一次使用BuildConfig.PACKAGE_NAME时,默认值是“android.support.multidex”。 - RasenKoD
1
谢谢你的答案,这对我很有帮助。我的错,我在开发过程中更改了包名,但忘记回去更新清单文件。啊!!!! - Aaron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接