Android-将原始资产中的文件保存到外部存储,以便其他应用程序访问,因为无法找到内容根异常

Android-将原始资产中的文件保存到外部存储,以便其他应用程序访问,因为无法找到内容根异常,android,android-intent,android-fileprovider,android-assets,Android,Android Intent,Android Fileprovider,Android Assets,我的原始资源目录中有一个文件,我正试图将其保存到共享电话存储中,该存储将允许其他应用打开并查看此视频 我可以使用以下代码将文件保存到本地应用程序存储或外部专用应用程序存储 Intent in = new Intent(Intent.ACTION_VIEW); // using getFilesDir() below causes this error: File videoFile = new File(getExternalFilesDirs(null)[1], &

我的原始资源目录中有一个文件,我正试图将其保存到共享电话存储中,该存储将允许其他应用打开并查看此视频

我可以使用以下代码将文件保存到本地应用程序存储或外部专用应用程序存储

    Intent in = new Intent(Intent.ACTION_VIEW);

    // using getFilesDir() below causes this error: 
    File videoFile = new File(getExternalFilesDirs(null)[1], "talking.mp4");

    // check if we have already copied file over
    if (!videoFile.exists()) {

        try {
            InputStream is = getResources().openRawResource(R.raw.talking);
            boolean newFile = videoFile.createNewFile();
            if (!newFile) {
                throw new Exception("Failed to create file");
            }
            OutputStream os = new FileOutputStream(videoFile);
            byte[] data = new byte[is.available()];
            is.read(data);
            os.write(data);
            is.close();
            os.close();
        } catch (IOException e) {
            Log.w("ExternalStorage", "Error writing " + videoFile, e);
            Toast.makeText(this, "Failed to copy talking.mp4", Toast.LENGTH_LONG).show();
            return;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // Line below 135  
    Uri uri =  FileProvider.getUriForFile(getApplicationContext(), getPackageName(), videoFile);
    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Problematic Line

    // type of file to view
    in.setDataAndType(uri, "video/*");

    // ask some other app to deal with it
    startActivity(in);
问题是我一直遇到这个错误:

Caused by: java.lang.IllegalArgumentException: Failed to find configured root that contains 
    /storage/1B12-3A08/Android/data/${getPackageName()}/files/talking.mp4

        at androidx.core.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:744)
        at androidx.core.content.FileProvider.getUriForFile(FileProvider.java:418)
        at ${getPackageName()}.MainActivity.btnPlayIntentClicked(MainActivity.java:135)
在这方面的帮助下,我做了一点快速的研究,并将其添加到我的清单中:

<application ... >
    //...
    <provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="${getPackageName()}"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/paths" />
    </provider> 
</application>
问题:

配置了可用的内容根目录后,我应该能够将文件从原始资源复制到外部私有存储,并请求Android(通过隐式意图)使用MX Player或VLC for Android播放视频

内容根配置缺少什么?(我添加了
外部文件路径
外部路径
,以便更好地测量)


@commonware回答后更新

我变了

File videoFile = new File(getExternalFilesDirs(null)[1], "talking.mp4");

这也是公正的

File videoFile = new File(getExternalFilesDirs(null)[0], "talking.mp4");
但这会产生相同的错误,但只是文件的另一个路径前缀:

Caused by: java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Android/data/${getPackageName()}/files/talking.mp4
我能够让文件的内容根工作,并传递文件Uri的意图,这给了选择打开VLC(Android)和其他一些,问题是没有应用程序可以播放该文件。我不记得我是怎么做到的


更新2

@BlackApps建议更改
res/xml/paths.xml
文件中的路径名,解决了这个问题

最初我有不同的名字,但它没有工作,也没有考虑在实验之后改变它们。

导致问题的原因:

内容根路径通过以下函数加载到应用程序启动:

FileProvider.parsePathStrategy(Context, String)
在内部,它通过使用相应的文件提供程序路径来创建所有路径的缓存(映射),以提供附加上下文(将路径附加到
中的指定路径)。给定输入:

<external-file name="some_name" path="MyAwesomeAssets"/>

将产生一个()目标路径(属于
环境。getExternalStorageDirectory()
),该路径在路径“MyAweomseAssets”之前,结果是输出路径为
/storage/simulated/0/MyAwesomeAssets

然后将其添加到缓存中,但在我的例子中,由于每个缓存都有相同的名称,因此它将简单地覆盖最后一条路径,即FIFO方法


因此,当我试图在我指定的内容根目录中获取文件的Uri时,只会找到一个,这将是
res/xml/path中定义的最后一个。xml
FileProvider
不支持可移动存储。将
getExternalFilesDir(null)[1]
更改为
getExternalFilesDir(null)
,或者您需要编写自己的
内容提供商
,从所需位置(或者直接从资产,如果您愿意的话)提供内容。

请参阅更新above@CybeX:
映射到
getExternalFilesDir(null)
,因此不清楚您的安装程序为什么不工作。您可能希望检查合并清单,确认您的
元素在那里并且没有更改--如果某个库碰巧也在使用您的相同权限字符串,可能是由于某种原因拾取了它的元数据。有关记录,这是一个新的VM-请检查清单和提供程序如上图所示-我很困惑。
name=“my_files”
您有三次相同的名称。请将它们改成不同的名称。@blackapps是的-这解决了问题。以前给过它不同的名称,但也没有帮助。不管怎样,您的答案解决了问题。
FileProvider.parsePathStrategy(Context, String)
<external-file name="some_name" path="MyAwesomeAssets"/>