Android O 上的 android.intent.action.SEND - URI 包含 file:// 网址而不是 content://
Posted
技术标签:
【中文标题】Android O 上的 android.intent.action.SEND - URI 包含 file:// 网址而不是 content://【英文标题】:android.intent.action.SEND on Android O - URI contains file:// urls instead of content:// 【发布时间】:2018-01-31 15:18:42 【问题描述】:我的应用通过这种方式在清单中注册操作发送:
<intent-filter >
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
<intent-filter >
<action android:name="android.intent.action.SEND_MULTIPLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
然后,要获取图片 uri,代码:
ArrayList<Uri> uris = new ArrayList<>();
switch(action)
case Intent.ACTION_SEND:
uris.add(getIntent().getParcelableExtra(Intent.EXTRA_STREAM));
break;
case Intent.ACTION_SEND_MULTIPLE:
uris = getIntent().getParcelableArrayListExtra(Intent.EXTRA_STREAM);
break;
我在 Android O 上遇到了不同的行为。在 O 之前的 Android 版本(4.4 到 7.1 测试)上,我得到了格式为 content://
的 URI,所以我使用了这个方法(在 *** 上找到)来解码uris 并将它们转换为直接图像路径:
public static String getRealPathFromUri(Context context, Uri contentUri)
Cursor cursor = null;
try
String[] proj = MediaStore.Images.Media.DATA;
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
finally
if (cursor != null)
cursor.close();
如上所述,在 Android 4.4 - 7.1 上一切正常。在 Android 8 上,intent 包含已解码的图像 uri,格式为 file://
,并且方法 getRealPathFromUri
会引发异常。
在搜索 Google 文档时,我找不到与 Android 8 中的该更改相关的任何内容。知道如何在 Android O 上获得相同的 uri 格式吗?
不确定是否重要,活动接收动作发送意图是这样定义的:
<activity
android:name=".SplashActivity"
android:label="@string/app_name"
android:launchMode="singleTask"
android:noHistory="true"
android:theme="@style/Theme.AppCompat.Light.NoActionBar.FullScreen">
<intent-filter>
有什么想法吗?
【问题讨论】:
如果您有 file:// uri,请不要使用 getRealPathFromUri。好吧,您永远不应该使用 getRealPathFromUri。不好的做法。 那么好的做法是什么?如果我有content://
uri,我必须使用getRealPathFromUri
。总是有 content://
uri,除了 Android 8 - 在 Android 8 上它总是 file://
。我想获得一致的解决方案 - 在所有 Android 版本上始终为content://
或始终为file://
。似乎在 android 8 上发生了一些变化
好的做法是同时支持这两种方法,并且永远不要尝试将内容 uri 转换为文件路径。也没有必要进行这样的转换。请说明您为什么需要它。
场景:打开系统图库,选择图片,分享到我的应用。我的应用程序接收图像 uri。然后我需要将图像上传到我的服务器。我需要直接的图像路径才能这样做。
无论如何我向您展示了如何在 uri 上打开输入流。然后就可以在decodeStream中使用输入流了。你还需要什么?
【参考方案1】:
我有一个答案。区别在于分享图片的app:https://play.google.com/store/apps/details?id=com.simplemobiletools.gallery
我的解决方案(我觉得不是最好的):
public static String getRealPathFromUri(Context context, Uri contentUri)
String path = contentUri.toString();
if(path.contains("file://"))
path = contentUri.getPath();
return path;
Cursor cursor = null;
try
String[] proj = MediaStore.Images.Media.DATA;
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
finally
if (cursor != null)
cursor.close();
【讨论】:
这是一个无意义的解决方案。当然,如果从路径开始,您只需从路径中删除 file:// 即可。但是您的应用尝试将内容方案转换为文件路径是错误的。 好吧,现在我需要弄清楚如何将 uri 作为额外的传递给 Intent,现在我正在使用字符串文件路径,这很简单。你是对的,在我的情况下,我不需要将内容方案转换为文件路径,但我可以想象有时需要它(例如,为应用用户显示图像位置)。 如果我的应用共享位于其私有内存中的图像,那么您的应用无法从接收到的内容方案中解码真实路径。您的方法之所以有效,是因为您使用了一些使用 MediaStore 的 Gallery 应用程序。迟早你会发现你自己。停止尝试获得真正的路径。 尝试写一个文件FileProvider app,然后分享一张图片。您将看到您的第一个应用程序无法解码真实路径。 我想知道 Android 8 上的应用如何发送 file:// 方案。因为这在 Android 7 中已经被禁止。该应用程序将获得 FileUriExposedException。【参考方案2】:使用 FileUtils.java 文件
FileUtils.java
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data)
File uploadFile = new File(FileUtils.getRealPath(activity.this, data.getData()));
【讨论】:
以上是关于Android O 上的 android.intent.action.SEND - URI 包含 file:// 网址而不是 content://的主要内容,如果未能解决你的问题,请参考以下文章
Assetlinks.json 中的应用链接意图过滤器在 Android 上不起作用
Android O 上的 android.intent.action.SEND - URI 包含 file:// 网址而不是 content://
值得你关注的Android8.0(Android O)上的重要变化