FileProvider crash-npe 试图在空字符串上调用 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 中的文件路径文件

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

我从互联网上下载了一段视频,并以这种方式保存到内存中:

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)
93423 次浏览

问题在于,在《清单》中,我有这样一句话:

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

当我调用 getUriForFile 时,我传递的是:

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

所以从 "com.example.asd"改成 "com.example.asd.fileprovider"就成功了

您可以不用硬编码软件包名称,而且还可以在同一个设备上运行多个变体(想想 releasedebugapplicationIdSuffix,参见 这些问题) :

基于 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,它没有找到 ContentProvider(info == null)。

将您的清单更改为(${applicationId}将由清单合并替换)

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

还有

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

如果您有一个实际的 ContentProvider,那么 .share后缀是可选的,最好使用包名作为权限。

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

现在不允许在 targetSdkVersion > = 24(Android N7.0)上附加 file://方案,所有设备(Android 5、6和7)总是只传递 content://。但是我们遇到了小米打破了谷歌的惯例,发送了 file://,因此 data.getData().getAuthority()给出了空字符串。

final String uriScheme = currentUri.getScheme();
if ("content".equals(uriScheme)) {
// getting full file path (works with some providers, i.e. 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
}

此外,在 Android Support Library v24.2.0中修复了导致 java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Android/data/com.example/files/attachments/image.jpg崩溃的 FileProvider.getUriForFile()错误。问题是 FileProvider.java 没有看到外部路径文件夹。

如果您在运行时使用 BuildConfig构建 AUTHORITY,请确保使用包括包名在内的完整类名。

坏:

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

好:

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

跟踪对我很管用。

mUri = FileProvider.getUriForFile(this,
BuildConfig.APPLICATION_ID + ".provider",
fileObject);

在我的例子中,我得到错误是因为

BuildConfig.APPLICATION_ID

是从

import android.support.v4.BuildConfig;

所以它返回的字符串是 "android.support.v4",而不是我的项目包名。检查导入文件是从您的 import project.Buildconfig而不是另一个。例如:

import com.example.yourProjectName.BuildConfig;

最后,在清单中的 <provider>标记中,我有 android:authorities="${applicationId}"来总是获得我的项目包名称作为权威

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


</application>


</manifest>

下面是我为解决这个问题所做的。我在 android 中给出了完全限定名: name。它可以在机器人6,7,8中工作

    <provider android:authorities="${applicationId}.opener.provider"
android:exported="false" android:grantUriPermissions="true"
android:name="io.github.pwlin.cordova.plugins.fileopener2.FileProvider">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths" />
</provider>

你应该试试:

  Context context = PostAdapter.this.activity;
StringBuilder stringBuilder2 = new StringBuilder();
stringBuilder2.append(PostAdapter.this.activity.getPackageName());
stringBuilder2.append(".provider");
Uri uri;
uri = FileProvider.getUriForFile(context,stringBuilder2.toString(), newFile);

这是你需要做的:

Uri fileURI = FileProvider.getUriForFile(getActivity(), getActivity().getPackageName() + ".fileprovider", file);