FileProvider crash - npe attempting to invoke XmlResourceParser on a null String
The problem was that in Manifest I had this line:
android:authorities="com.example.asd.fileprovider"
and when calling getUriForFile I was passing:
Uri contentUri = FileProvider.getUriForFile(getApplicationContext(), "com.example.asd", newFile);
So changed from "com.example.asd"
to "com.example.asd.fileprovider"
and it worked
You can do this without hardcoding the package name with an additional benefit of being able to run multiple variants on the same device (think release
and debug
with applicationIdSuffix
, see these issues):
Based on 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);
you were using the wrong authority
and it didn't find the ContentProvider
(info == null
).
Change your manifest to (${applicationId}
will be replaced by Manifest Merger)
android:authorities="${applicationId}.share"
and
Uri uri = FileProvider.getUriForFile(context, context.getPackageName() + ".share", result);
The .share
suffix is optional, in case you have a real ContentProvider
which is better to have the package name as the authority.
In my case, I got the error because the
BuildConfig.APPLICATION_ID
was being imported from
import android.support.v4.BuildConfig;
So the string it returned was "android.support.v4"
instead of my project package name. Check out the import file is from your import project.Buildconfig
and not another. Example:
import com.example.yourProjectName.BuildConfig;
Finally, in <provider>
tag in Manifest I have android:authorities="${applicationId}"
to always get my project package name as the authority
<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>
First, be sure that you provider android:authorities
does not conflict with your other providers. Besides that you may choose any name for the last part of its name: "provider", "fileprovider" etc., but app crashes when there are more than one android:authorities
listed, while documentation states that it allows multiple values listed.
file://
scheme is now not allowed to be attached with Intent on targetSdkVersion >= 24 (Android N 7.0), only content://
is always passed for all devices (Android 5, 6 and 7). But we encountered that Xiaomi breaks this Google convention and sends file://
, hence data.getData().getAuthority()
gives empty string.
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
}
Also, the bug when FileProvider.getUriForFile()
resulted in crash java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Android/data/com.example/files/attachments/image.jpg
was fixed in Android Support Library v24.2.0. The problem was that FileProvider.java did not see external-path folders.