FileProvider崩溃-NPE尝试在空字符串上调用XmlResourceParser


139

这是我的清单的一部分:

<?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中的filepaths文件

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

“这是文件路径文件”-该文件在您项目中的确切位置?
CommonsWare 2015年

1
raw / xml / filepaths.xml
2015年

2
在权限中,我将.provider附加到应用程序包中,但是在调用getUriForFile时,我不附加.provider。即时通讯,即时通讯正在测试
JK

4
是的,这就是问题所在
JK 2015年

Answers:


264

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

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

当调用getUriForFile时,我正在传递:

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

因此从"com.example.asd"改为"com.example.asd.fileprovider"有效


1
谢谢为我工作。首先,我就是这样。android:authorities =“ $ {applicationId} .fileprovider现在,我将其更改为com.memecreator.fileprovider我的实际包名称
Rayyan

2
同意@Rayyan,最好android:authorities="${applicationId}"始终使用;代码永远不会出错。
sud007

为我工作。谢谢
landrykapela

2
该解决方案对我不起作用...在检查以确保这是正确的之后,仍然出现空指针异常。
韦斯利·弗兰克

44

你可以做到这一点没有用的能够运行在同一台设备(想想在多个变种一个额外的好处硬编码的包名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,但找不到ContentProviderinfo == null)。

将清单更改为(${applicationId}将被清单合并代替)

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

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

.share后缀是可选的,如果你有一个真正的ContentProvider这是更好地为有权威的包名。


工作对我来说...我用最后两行及其工作perfectly..Thanks
拉温德拉Kushwaha

24

就我而言,我得到了错误,因为

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>

1
什么是android:resource =“ @ xml / ruta_fileprovider”
Ananta Prasad

1
@AnantaPrasad <?xml版本=“ 1.0”编码=“ utf-8”?> <路径> <外部路径名=“ external_files”路径=“。/> <files-path name =“ files” path =“。” /> <cache-path name =“ cache” path =“。” /> </ paths>
王子

5

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

file://现在,不允许在targetSdkVersion> = 24(Android N 7.0)上使用Intent附加方案,仅对content://所有设备(Android 5、6和7)始终传递该方案。但是我们遇到了小米违反了这个Google约定并发送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
}

另外,FileProvider.getUriForFile()导致崩溃的错误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没有看到外部路径文件夹。


1

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

坏:

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

好:

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


0

以下对我有用。

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

0

这是我为解决此问题所做的工作。我在android:name中给出了完全限定的名称。它在Android 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>

您能否使用内部目录中的文件提供程序共享用于共享文件的代码?
Vishal Patoliya 1818年

0

你应该试试看:

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

0

这是您需要做的:

Uri fileURI = FileProvider.getUriForFile(getActivity(), getActivity().getPackageName() + ".fileprovider", file);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.