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)上的重要变化

Google I/O 大会上的 Android Things 亮点汇总

不通过百川打开淘宝app