Action.Picker returns invalid/wrong Uri(如何从多个选取的图库 img 中获取路径或 byte[])

Action.Picker returns invalid/wrong Uri (How to get path or byte[] from multiple picked gallery img)

我有一个表单应用程序,我需要从 phone 存储中选择“一对多”图像。 为此,我使用依赖注入系统。

我的问题是我在某处得到一个 Android.netUri 解析为一个不存在的文件...以及一个我以前从未见过的文件名。 更重要的是,如果我选择在过去几个小时内拍摄的照片,则此代码有效...

我已经走到尽头了,我真的希望有人能指出我做错了什么。

我启动选择器 activity 使用:

[assembly: Dependency(typeof(ImagePickerService))]
namespace MyApp.Droid
{
    public class ImagePickerService : Java.Lang.Object, IImagePickerService
    {
        public async Task OpenGallery()
        {
            try
            {
                var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Storage);
                if (status != PermissionStatus.Granted)
                {
                    if (await CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync(Permission.Storage))
                    {
                        Toast.MakeText(CrossCurrentActivity.Current.Activity, "Need Storage permission to access to your photos.", ToastLength.Long).Show();
                    }

                    var results = await CrossPermissions.Current.RequestPermissionsAsync(new[] { Permission.Storage });
                    status = results[Permission.Storage];
                }

                if (status == PermissionStatus.Granted)
                {
                    Toast.MakeText(CrossCurrentActivity.Current.Activity, "Pick max 20 images", ToastLength.Long).Show();
                    var imageIntent = new Intent(Intent.ActionPick);
                    imageIntent.SetType("image/*");
                    imageIntent.PutExtra(Intent.ExtraAllowMultiple, true);
                    imageIntent.SetAction(Intent.ActionPick);
                    CrossCurrentActivity.Current.Activity.StartActivityForResult(Intent.CreateChooser(imageIntent, "Pick pictures"), 100);

                }
                else if (status != PermissionStatus.Unknown)
                {
                    Toast.MakeText(CrossCurrentActivity.Current.Activity, "Permission Denied. Can not continue, try again.", ToastLength.Long).Show();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                Toast.MakeText(CrossCurrentActivity.Current.Activity, "Error. Can not continue, try again.", ToastLength.Long).Show();
            }
        }

    }

然后在我的 MainActivity.cs 我有 OnActivityResult 我曾尝试使用 ContentResolver.OpenInputStream 来获取图像字节,但没有成功,所以这被注释掉了 atm。

        protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
        {
            base.OnActivityResult(requestCode, resultCode, data);

            if (requestCode == OPENGALLERYCODE && resultCode == Result.Ok)
            {
                List<string> images = new List<string>();

                if (data != null)
                {
                    ClipData clipData = data.ClipData;
                    if (clipData != null)
                    {
                        for (int i = 0; i < clipData.ItemCount; i++)
                        {
                            ClipData.Item item = clipData.GetItemAt(i);
                            /*
                            var stream = ContentResolver.OpenInputStream(item.Uri); //This throws "FileNotFound"
                            byte[] byteArray;
                            using (var memoryStream = new MemoryStream())
                            {
                                stream.CopyTo(memoryStream);
                                byteArray = memoryStream.ToArray();
                                stream.Close();
                                stream = null;
                            }
                            stream = ContentResolver.OpenInputStream(item.Uri);
                            var exif = new ExifInterface(stream);
                            stream.Close();
                            */

                            Android.Net.Uri uri = item.Uri;
                            var path = GetActualPathFromFile(uri);

                            if (path != null)
                            {
                                var tmpImgPath = RotateToOriginalDimention(path);
                                images.Add(tmpImgPath);
                            }
                        }
                    }
                    else
                    {
                        Android.Net.Uri uri = data.Data;
                        var path = GetActualPathFromFile(uri);

                        if (path != null)
                        {
                            var tmpImgPath = RotateToOriginalDimention(path);
                            images.Add(tmpImgPath);
                        }
                    }
                    MessagingCenter.Send<App, List<string>>((App)Xamarin.Forms.Application.Current, "ImagesSelected", images);
                }
            }
        }

还有 GetActualPathFromFile(也在我的 MainActivity.cs 中) 孔函数在下面,但我点击了这部分代码并到达 "FileNotFound"

(...)
                else if ("content".Equals(uri.Scheme, StringComparison.OrdinalIgnoreCase))
                {

                    var retval2 = getDataColumn(this, uri, null, null);
                    if (File.Exists(retval2)) //<----------------------- This returns "false"
                    {
                        return retval2;
                    }
                    else
                    {
                        throw new Exception("file not found " + retval2);
                    }
                }
(...)

GetActualPathFromFile 这个洞

        private string GetActualPathFromFile(Android.Net.Uri uri)
        {
            bool isKitKat = Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Kitkat;

            if (isKitKat && DocumentsContract.IsDocumentUri(this, uri))
            {
                // ExternalStorageProvider
                if (isExternalStorageDocument(uri))
                {
                    string docId = DocumentsContract.GetDocumentId(uri);

                    char[] chars = { ':' };
                    string[] split = docId.Split(chars);
                    string type = split[0];

                    if ("primary".Equals(type, StringComparison.OrdinalIgnoreCase))
                    {
                        var retval = Android.OS.Environment.ExternalStorageDirectory + "/" + split[1];
                        if (File.Exists(retval))
                        {
                            return retval;
                        }
                        else
                        {
                            throw new Exception("file not found " + retval);
                        }
                    }
                }
                // DownloadsProvider
                else if (isDownloadsDocument(uri))
                {
                    string id = DocumentsContract.GetDocumentId(uri);

                    Android.Net.Uri contentUri = ContentUris.WithAppendedId(
                                    Android.Net.Uri.Parse("content://downloads/public_downloads"), long.Parse(id));

                    //System.Diagnostics.Debug.WriteLine(contentUri.ToString());

                    var retval = getDataColumn(this, contentUri, null, null);
                    if (File.Exists(retval))
                    {
                        return retval;
                    }
                    else
                    {
                        throw new Exception("file not found " + retval);
                    }
                }
                // MediaProvider
                else if (isMediaDocument(uri))
                {
                    String docId = DocumentsContract.GetDocumentId(uri);

                    char[] chars = { ':' };
                    String[] split = docId.Split(chars);

                    String type = split[0];

                    Android.Net.Uri contentUri = null;
                    if ("image".Equals(type))
                    {
                        contentUri = MediaStore.Images.Media.ExternalContentUri;
                    }
                    else if ("video".Equals(type))
                    {
                        contentUri = MediaStore.Video.Media.ExternalContentUri;
                    }
                    else if ("audio".Equals(type))
                    {
                        contentUri = MediaStore.Audio.Media.ExternalContentUri;
                    }

                    String selection = "_id=?";
                    String[] selectionArgs = new String[]
                    {
                        split[1]
                    };

                    var retval = getDataColumn(this, contentUri, selection, selectionArgs);
                    if (File.Exists(retval))
                    {
                        return retval;
                    }
                    else
                    {
                        throw new Exception("file not found " + retval);
                    }
                }
            }
            // MediaStore (and general)
            else if ("content".Equals(uri.Scheme, StringComparison.OrdinalIgnoreCase))
            {

                // Return the remote address
                if (isGooglePhotosUri(uri))
                {
                    var retval = uri.LastPathSegment;
                    if (File.Exists(retval))
                    {
                        return retval;
                    }
                    else
                    {
                        throw new Exception("file not found " + retval);
                    }
                }


                var retval2 = getDataColumn(this, uri, null, null);
                if (File.Exists(retval2))
                {
                    return retval2;
                }
                else
                {
                    throw new Exception("file not found " + retval2);
                }
            }
            // File
            else if ("file".Equals(uri.Scheme, StringComparison.OrdinalIgnoreCase))
            {
                var retval = uri.Path;
                if (File.Exists(retval))
                {
                    return retval;
                }
                else
                {
                    throw new Exception("file not found " + retval);
                }
            }

            throw new Exception("file not found ");
        }

        public static String getDataColumn(Context context, Android.Net.Uri uri, String selection, String[] selectionArgs)
        {
            ICursor cursor = null;
            String column = "_data";
            String[] projection =
            {
                column
            };

            try
            {
                cursor = context.ContentResolver.Query(uri, projection, selection, selectionArgs, null);
                if (cursor != null && cursor.MoveToFirst())
                {
                    int index = cursor.GetColumnIndexOrThrow(column);
                    return cursor.GetString(index);
                }
            }
            finally
            {
                if (cursor != null)
                    cursor.Close();
            }
            return null;
        }

        //Whether the Uri authority is ExternalStorageProvider.
        public static bool isExternalStorageDocument(Android.Net.Uri uri)
        {
            return "com.android.externalstorage.documents".Equals(uri.Authority);
        }

        //Whether the Uri authority is DownloadsProvider.
        public static bool isDownloadsDocument(Android.Net.Uri uri)
        {
            return "com.android.providers.downloads.documents".Equals(uri.Authority);
        }

        //Whether the Uri authority is MediaProvider.
        public static bool isMediaDocument(Android.Net.Uri uri)
        {
            return "com.android.providers.media.documents".Equals(uri.Authority);
        }

        //Whether the Uri authority is Google Photos.
        public static bool isGooglePhotosUri(Android.Net.Uri uri)
        {
            return "com.google.android.apps.photos.content".Equals(uri.Authority);
        }

发现真正的问题是 Google 照片应用程序没有更新并且仍然显示已删除的图像。

phone 重启 2 次后,Google 照片应用终于更新了。 所以这看起来更像是 Google Foto 的缓存问题,而不是 xamarin 问题。