【问题标题】:FileProvider crash - npe attempting to invoke XmlResourceParser on a null StringFileProvider 崩溃 - npe 尝试在空字符串上调用 XmlResourceParser
【发布时间】:2015-06-17 15:35:24
【问题描述】:

这是我清单的一部分:

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

【问题讨论】:

  • "This is the filepaths file" -- 这个文件到底在你的项目中的什么位置?
  • 原始/xml/filepaths.xml
  • 在权限中我有.provider,附加到应用程序包,但是在调用getUriForFile时,我没有附加.provider。也许就是这样,我现在正在测试
  • 是的,这就是问题

标签: android


【解决方案1】:

问题是在 Manifest 我有这行:

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

当我调用 getUriForFile 时:

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

所以从 "com.example.asd" 更改为 "com.example.asd.fileprovider" 并且它起作用了

【讨论】:

  • 感谢为我工作。首先我是这样做的。 android:authorities="${applicationId}.fileprovider 现在我把它改成了 com.memecreator.fileprovider 我的实际包名
  • 同意@Rayyan,最好始终使用android:authorities="${applicationId}";代码永远不会出错。
  • 为我工作。谢谢
  • 这个解决方案对我不起作用......在检查以确保这是正确的之后,我仍然收到空指针异常。
【解决方案2】:

您可以在不硬编码包名称的情况下执行此操作,另外还有一个好处是能够在同一设备上运行多个变体(想想releasedebugapplicationIdSuffix,请参阅these issues):

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

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

【讨论】:

  • 为我工作......我已经使用了最后两行并且它的工作完美......谢谢
【解决方案3】:

在我的情况下,我收到错误是因为

BuildConfig.APPLICATION_ID

正在从

导入
import android.support.v4.BuildConfig;

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

import com.example.yourProjectName.BuildConfig;

最后,在 Manifest 的 &lt;provider&gt; 标记中,我有 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:resource="@xml/ruta_fileprovider"
  • @AnantaPrasad
【解决方案4】:

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

file:// 方案现在不允许在 targetSdkVersion >= 24 (Android N 7.0) 上附加 Intent,只有 content:// 始终传递给所有设备(Android 5、6 和 7)。但是我们遇到了小米打破了这个谷歌约定并发送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 没有看到外部路径文件夹。

【讨论】:

    【解决方案5】:

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

    不好:

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

    好:

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

    【讨论】:

      【解决方案6】:

      以下对我有用。

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

      【讨论】:

        【解决方案7】:

        这是我为解决此问题所做的。我在 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>
        

        【讨论】:

        • 您能否使用内部目录中的文件提供程序共享您的共享文件代码?
        【解决方案8】:

        你应该试试:

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

        【讨论】:

          【解决方案9】:

          这是你需要做的:

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

          【讨论】:

            猜你喜欢
            • 2017-12-02
            • 1970-01-01
            • 2023-03-14
            • 1970-01-01
            • 1970-01-01
            • 2013-01-07
            • 2012-05-13
            • 2018-11-22
            • 1970-01-01
            相关资源
            最近更新 更多