Action.Picker 返回无效/错误的 Uri(如何从多个选取的图库 img 中获取路径或字节 [])
Posted
技术标签:
【中文标题】Action.Picker 返回无效/错误的 Uri(如何从多个选取的图库 img 中获取路径或字节 [])【英文标题】:Action.Picker returns invalid/wrong Uri (How to get path or byte[] from multiple picked gallery img) 【发布时间】:2019-02-15 18:20:57 【问题描述】:我有一个表单应用程序,我需要从手机存储中选择“一对多”图像。 为此,我使用依赖注入系统。
我的问题是我得到一个 android.netUri 的地方,它解析为一个不存在的文件......以及一个我以前从未见过的文件名。 更重要的是,如果我选择在过去几个小时内拍摄的照片,这个代码就可以工作......
我已经走到了尽头,我真的希望有人能指出我做错了什么。
我用以下方式启动 Picker 活动:
[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);
【问题讨论】:
【参考方案1】:发现真正的问题是 Google 相册应用没有更新,并且仍在显示已删除的图像。
在手机重启 2 次后,Google 相册应用终于更新了。 所以这看起来更像是 Google Foto 的缓存问题,而不是 xamarin 问题。
【讨论】:
以上是关于Action.Picker 返回无效/错误的 Uri(如何从多个选取的图库 img 中获取路径或字节 [])的主要内容,如果未能解决你的问题,请参考以下文章
Flutter 错误:无效参数:URI 文件中未指定主机:///null