我编写了一个将某些数据导出到文件的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
返回的路径),然后访问文件在那里,但这两个行为都有严重的缺点(由于不必要的许可或糟糕的用户体验导致的安全影响)。
我可以使用其他任何选项来使其正常工作吗?
答案 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://,,您无法访问这些文件。