如果我的应用没有READ_EXTERNAL_STORAGE

时间:2017-03-16 22:30:53

标签: android android-intent android-permissions intentfilter android-external-storage

我编写了一个将某些数据导出到文件的Android应用程序。

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

现在,同一个故事的另一面是该应用程序应该能够接收一个文件来导入它。我的目的是让用户在文件管理器中选择一个文件并选择" Share"选项。现在我的intent-filter应该被激活,我的应用应该访问该文件。

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

根据Intent类的文档,如果调用应用添加了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();
    }
}

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

结果是:

  • 我尝试使用ES文件浏览器和Amaze来分享&#34;分享&#34;文件到我的应用程序。通常,收到的Uri是文件Uri ("file://" scheme),尝试打开此文件会在openInputStream上失败,并显示我的应用无法访问该文件的信息。

  • 当我出于某种原因从ES文件浏览器共享文件是媒体文件时,行为会发生变化。我收到"content://" Uri,我的应用可以访问该文件。 Amaze似乎仍然发送"file://" Uri并打开文件失败。

  • 我尝试修改代码以从ClipData获取Uris(如果可用),但它没有改变任何内容。

  • 当我尝试从内置MIUI电子邮件客户端打开附件时,我还会收到file:// Uris,并且无法访问该文件。 (为了测试这一点,我必须使用ACTION_VIEW操作而不是ACTION_SEND

我也试过了另一种方式。我使用ACTION_GET_CONTENT Intent从我的应用调用了一个文件选择器,并希望使用我应用中返回的Uri。结果更糟,因为即使"content://" Uris也不起作用。

所以问题是 - 是否有办法访问流行文件管理器共享的文件,允许我的应用访问共享文件而不添加READ_EXTERNAL_STORAGE permission?< / p>

我可以阅读关于FLAG_GRANT_READ_URI_PERMISSION的Android文档,并且从{strong> 7.0 开始禁止file:// Uris,所以理论上一切都准备好让它工作,但在真实世界我碰到了墙......

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

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

2 个答案:

答案 0 :(得分:0)

  

根据Intent类的文档,如果调用应用程序添加FLAG_GRANT_READ_URI_PERMISSION,那么无论如何都应该让我的应用程序读取共享文件。

仅适用于content计划。

  

我使用ACTION_GET_CONTENT Intent从我的应用程序调用了一个文件选择器,并希望使用我的应用程序中返回的Uri。结果甚至更糟,因为即使&#34;内容://&#34; Uris不起作用。

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

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

  

有没有办法以允许我的应用访问共享文件而不添加READ_EXTERNAL_STORAGE权限的方式访问流行文件管理器共享的文件?

如果他们为您提供file Uri,则不会。不幸的是,ACTION_SEND不提供按方案过滤。 : - (

现在,从长远来看,file Uri值会逐渐淡出,因为Android 7.0+会破坏尝试将其包含在Intent中的应用,以及targetSdkVersion的应用1 +} 24+。

答案 1 :(得分:0)

Android在支持库中引入了FileProvider类,用于在其他应用中共享文件。这是出于安全原因而引入的。

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

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