如果我的应用程序没有 READ_EXTERNAL_STORAGE,如何访问文件管理器共享的文件

How to access a file shared by a file manager if my app does not have READ_EXTERNAL_STORAGE

我编写了一个 Android 应用程序,可以将一些数据导出到文件中。

该文件通过 ACTION_SEND Intent 和我的自定义 ContentProvider 发布到其他应用程序。它工作正常。文件可以附加到电子邮件或通过 Bluetooth.

发送

现在,同一个故事的另一面是应用程序应该能够接收文件以将其导入。我的意图是让用户 select 文件管理器中的文件和 select "Share" 选项。现在我的 intent-filter 应该被激活,我的应用程序应该可以访问该文件。

我的应用程序没有READ_EXTERNAL_STORAGE权限,因为它通常不需要访问外部存储中的文件。我不想添加此权限,我不想吓唬用户我的应用可能会访问他们的照片等等。

根据Intentclass的文档,如果调用应用添加了FLAG_GRANT_READ_URI_PERMISSION,应该足以让我的应用读取共享文件了。

我的intent-filter:

<intent-filter>
    <action android:name="android.intent.action.SEND"/>
    <action android:name="android.intent.action.SENDTO"/>
    <action android:name="android.intent.action.SEND_MULTIPLE"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <category android:name="android.intent.category.BROWSABLE"/>
    <data android:mimeType="*/*"/>
</intent-filter>

我处理通过 intent-filter 接收到的 Intent 的代码:

Uri uri = null;
if (uri == null)
{
    uri = intent.getData();
}
if (uri == null)
{
    if (Intent.ACTION_SEND_MULTIPLE.equals(intent.getAction()))
    {
        uri = (Uri) intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM).get(0);
    }
    else
    {
        uri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
    }
}
if (uri != null)
{
    try
    {
        InputStream stream = getContentResolver().openInputStream(uri);
        stream.read();
        stream.close();
        Toast.makeText(this, "Success " + intent.getAction() + " " + uri.toString(), Toast.LENGTH_LONG).show();
    }
    catch (IOException e)
    {
        Toast.makeText(this, "Error " + intent.getAction() + " " + uri.toString() + " " + e.getMessage(), Toast.LENGTH_LONG).show();
    }
}

这只是一个 "test" 代码,所以我只是尝试从文件的开头读取任何内容以检查它是否有效。

结果是:

另外一种方法我也试过了。我使用 ACTION_GET_CONTENT Intent 从我的应用程序调用了一个文件选择器,并想使用从我的应用程序返回的 Uri。结果更糟,因为连"content://" Uris都不行。

所以问题是 - 有没有什么方法可以让我的应用无需添加 READ_EXTERNAL_STORAGE permission?

我可以在 Android 文档中读到关于 FLAG_GRANT_READ_URI_PERMISSION 并且 file:// Uris 从 Android 7.0 开始被禁止,所以理论上一切都已准备就绪,但在现实世界中我碰壁了...

我知道我可以随时为我的应用程序添加 READ_EXTERNAL_STORAGE 权限或要求用户手动将文件复制到我的应用程序的外部存储目录(由 getExternalFilesDir 返回的路径),然后访问那里的文件,但是这两种行为都有严重的缺点(不必要的权限或糟糕的用户体验导致安全影响)。

我可以使用任何其他选项来使其正常工作吗?

According to the documentation of the Intent class, if the calling app adds FLAG_GRANT_READ_URI_PERMISSION, it should be enough to let my app read the shared file anyway.

这仅适用于 content 方案。

I invoked a file picker from my app using ACTION_GET_CONTENT Intent and wanted to use the returned Uri from my app. The result was even worse, because even "content://" Uris do not work.

您的代码中可能存在错误。您可以考虑为此打开一个单独的 Stack Overflow 问题。

此外,对于 API 19 级以上,您可以使用 ACTION_OPEN_DOCUMENT,这是推荐的 Intent 操作。

is there any way to access the files shared from the popular file managers in a way that allows my app to access the shared file without adding READ_EXTERNAL_STORAGE permission?

如果他们给你 file Uri 就不会。不幸的是 ACTION_SEND 不提供按方案过滤。 :-(

现在,从长远来看,file Uri 值将会淡出,因为 Android 7.0+ 破坏了试图将它们包含在 Intent 中的应用程序,对于 targetSdkVersion 为 24+ 的应用。

Android 在支持库中引入了 FileProvider class 以在其他应用程序之间共享文件。这是出于安全原因引入的。

显然在 android 7.0 中您无法访问带有文件前缀的 URI。

除非并且直到文件管理器提供 URI content:// 而不是 file://, 您无法访问这些文件。