FileProvider crash – npe尝试调用空string上的XmlResourceParser

这是我清单的一部分:

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.asd" android:versionCode="118" android:versionName="118" > <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="19" /> <application android:name="com.example.asd.AsdApplication" android:allowBackup="true" android:allowTaskReparenting="true" android:theme="@style/AsdTheme" > ... <provider android:name="com.example.asd.database.hq.ContentProviderDB" android:authorities="ourContentProviderAuthorities" > </provider> <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.example.asd.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths" /> </provider> ... </application> </manifest> 

这是raw / xml / filepaths.xml中的文件path文件

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

我从互联网下载一个video,并将其保存到内部存储:

 public static boolean saveInputStreamToInternalStorageFile(Context context, String filename, byte[] dataToWrite, Context ctx) { FileOutputStream fos; try { fos = new FileOutputStream(context.getFilesDir() + File.separator + filename); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(dataToWrite); oos.close(); return true; } catch (FileNotFoundException e) { e.printStackTrace(); return false; } catch (IOException e) { e.printStackTrace(); return false; } } 

我尝试像这样使用它:

 private void playVideoFromDeviceWithWorkaround(String fileName) { File newFile = new File(getFilesDir(), fileName); Uri contentUri = FileProvider.getUriForFile(getApplicationContext(), "com.example.asd", newFile); try { vvVideoFullscreen.setVideoURI(contentUri); showMediaControls = true; playVideo(); } catch (Exception e) { playVideoFromNetwork(); } } 

在这条线上:

 Uri contentUri = FileProvider.getUriForFile(getApplicationContext(), "com.example.asd", newFile); 

我得到以下错误:

 java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.ProviderInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference at android.support.v4.content.FileProvider.parsePathStrategy(FileProvider.java:560) at android.support.v4.content.FileProvider.getPathStrategy(FileProvider.java:534) at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:376) 

问题是在清单中我有这样一行:

 android:authorities="com.example.asd.fileprovider" 

当调用getUriForFile时,我传递:

 Uri contentUri = FileProvider.getUriForFile(getApplicationContext(), "com.example.asd", newFile); 

因此,从"com.example.asd"更改为"com.example.asd.fileprovider" ,它的工作

您可以在不对包名进行硬编码的情况下执行此操作,还可以在同一设备上运行多个变体(请参阅applicationIdSuffix releasedebug ,请参阅以下问题 ):

基于FileProvider.java:560

 final ProviderInfo info = context.getPackageManager() .resolveContentProvider(authority, PackageManager.GET_META_DATA); final XmlResourceParser in = info.loadXmlMetaData( //560 context.getPackageManager(), META_DATA_FILE_PROVIDER_PATHS); 

你使用了错误的authority ,它没有findContentProviderinfo == null )。

更改您的清单到( ${applicationId}将被清单合并取代)

 android:authorities="${applicationId}.share" 

 Uri uri = FileProvider.getUriForFile(context, context.getPackageName() + ".share", result); 

.share后缀是可选的,以防你拥有一个真正的ContentProvider ,它最好拥有包名作为权限。

首先,请确保您的提供者android:authorities不与您的其他提供者冲突。 除此之外,你可以select任何名字的最后部分名称:“供应商”,“文件提供者”等,但应用程序崩溃时,有多个android:authorities列出,而文档指出,它允许列出多个值。

file:// scheme目前不允许在targetSdkVersion> = 24(Android N 7.0)上的Intent上附加,所有设备(Android 5,6和7)都只传递content:// 。 但是我们遇到了小米打破这个Google约定并发送file:// ,因此data.getData().getAuthority()给出了空string。

 final String uriScheme = currentUri.getScheme(); if ("content".equals(uriScheme)) { // getting full file path (works with some providers, ie Gallery) path = FileUtils.getPath(getContext(), currentUri); if (path != null) { currentFile = new File(path); } } else if ("file".equals(uriScheme)) { // in a rare case we received file:// in currentUri, we need to: // 1. create new File variable from currentUri that looks like "file:///storage/emulated/0/download/50044382b.jpg" // 2. generate a proper content:// Uri for it currentFile = new File(currentUri.getPath()); String authority = data.getData().getAuthority(); if (authority != null && !authority.isEmpty()) { currentUri = FileProvider.getUriForFile(getActivity(), authority, currentFile); } } else { // throw exception } 

另外, FileProvider.getUriForFile()导致崩溃的bug java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Android/data/com.example/files/attachments/image.jpg在Android支持库v24.2.0。 问题是FileProvider.java没有看到外部path文件夹。

如果您使用BuildConfig在运行时构buildAUTHORITY,请确保使用完整的类名称(包括您的包名称)。

坏:

final String AUTHORITY = BuildConfig.APPLICATION_ID + ".provider";

好:

final String AUTHORITY = com.mycompany.myapp.BuildConfig.APPLICATION_ID + ".provider";