如果我的应用程序没有 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
权限,因为它通常不需要访问外部存储中的文件。我不想添加此权限,我不想吓唬用户我的应用可能会访问他们的照片等等。
根据Intent
class的文档,如果调用应用添加了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" 代码,所以我只是尝试从文件的开头读取任何内容以检查它是否有效。
结果是:
我尝试使用 ES 文件资源管理器和 Amaze 将 "share" 文件添加到我的应用程序。通常收到的 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
?
我可以在 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://, 您无法访问这些文件。
我编写了一个 Android 应用程序,可以将一些数据导出到文件中。
该文件通过 ACTION_SEND
Intent
和我的自定义 ContentProvider
发布到其他应用程序。它工作正常。文件可以附加到电子邮件或通过 Bluetooth
.
现在,同一个故事的另一面是应用程序应该能够接收文件以将其导入。我的意图是让用户 select 文件管理器中的文件和 select "Share" 选项。现在我的 intent-filter
应该被激活,我的应用程序应该可以访问该文件。
我的应用程序没有READ_EXTERNAL_STORAGE
权限,因为它通常不需要访问外部存储中的文件。我不想添加此权限,我不想吓唬用户我的应用可能会访问他们的照片等等。
根据Intent
class的文档,如果调用应用添加了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" 代码,所以我只是尝试从文件的开头读取任何内容以检查它是否有效。
结果是:
我尝试使用 ES 文件资源管理器和 Amaze 将 "share" 文件添加到我的应用程序。通常收到的
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
?
我可以在 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://, 您无法访问这些文件。