I want to get actual path from Uri, when I select file using intent then it will be returning URI but below line of code not working for conversion URI to string path
Open FilePicker
public static void PickFile(Activity context)
{
Intent intent = new Intent(Intent.ActionGetContent);
intent.SetType("*/*");
context.StartActivityForResult(intent, PICKFILE_RESULT_CODE);
}
Get Result
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
if(requestCode == PICKFILE_RESULT_CODE)
{
string filepath = GetRealPathFromURI(MainActivity.act, data.Data);
}
}
public static string GetRealPathFromURI(Activity act, Android.Net.Uri contentURI)
{
try
{
ICursor cursor = act.ContentResolver.Query(contentURI, null, null, null, null);
cursor.MoveToFirst();
string documentId = cursor.GetString(0);
documentId = documentId.Split(':')[1];
cursor.Close();
cursor = act.ContentResolver.Query(
MediaStore.Images.Media.ExternalContentUri,
null, MediaStore.Images.Media.InterfaceConsts.Id + " = ? ", new[] { documentId }, null);
cursor.MoveToFirst();
string path = cursor.GetString(cursor.GetColumnIndex(MediaStore.Images.Media.InterfaceConsts.Data));
cursor.Close();
return path;
}
catch(Exception e)
{
Log.Debug("TAG_DATA",e.ToString());
return "";
}
}
Error
System.IndexOutOfRangeException: Index was outside the bounds of the
array.
can anyone explain to me, what's wrong think I am doing in this code.
How to get actual path from Uri xamarin android
I note that you are using MediaStore.Images.Media.ExternalContentUri
property, what you want is getting the real path of Gallery Image?
If you want implement this feature, you could read my answer : Get Path of Gallery Image ?
private string GetRealPathFromURI(Android.Net.Uri uri)
{
string doc_id = "";
using (var c1 = ContentResolver.Query(uri, null, null, null, null))
{
c1.MoveToFirst();
string document_id = c1.GetString(0);
doc_id = document_id.Substring(document_id.LastIndexOf(":") + 1);
}
string path = null;
// The projection contains the columns we want to return in our query.
string selection = Android.Provider.MediaStore.Images.Media.InterfaceConsts.Id + " =? ";
using (var cursor = ContentResolver.Query(Android.Provider.MediaStore.Images.Media.ExternalContentUri, null, selection, new string[] { doc_id }, null))
{
if (cursor == null) return path;
var columnIndex = cursor.GetColumnIndexOrThrow(Android.Provider.MediaStore.Images.Media.InterfaceConsts.Data);
cursor.MoveToFirst();
path = cursor.GetString(columnIndex);
}
return path;
}
Update :
Here is a solution :
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))
{
return Android.OS.Environment.ExternalStorageDirectory + "/" + split[1];
}
}
// 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());
return getDataColumn(this, contentUri, null, null);
}
// 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]
};
return getDataColumn(this, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".Equals(uri.Scheme, StringComparison.OrdinalIgnoreCase))
{
// Return the remote address
if (isGooglePhotosUri(uri))
return uri.LastPathSegment;
return getDataColumn(this, uri, null, null);
}
// File
else if ("file".Equals(uri.Scheme, StringComparison.OrdinalIgnoreCase))
{
return uri.Path;
}
return null;
}
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);
}
Get the actual path in OnActivityResult
:
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if (requestCode == 0)
{
var uri = data.Data;
string path = GetActualPathFromFile(uri);
System.Diagnostics.Debug.WriteLine("Image path == " + path);
}
}
Read this article, you will get exactly simple answer.
https://commonsware.com/blog/2016/03/15/how-consume-content-uri.html
My code as below:
var targetPath = $"{FileDir}{Path.DirectorySeparatorChar}{FileName}";
const int bufferSize = 1024;
using (var inputStream = Activity.ContentResolver.OpenInputStream(audioFileUri))
{
using (var outputStream = File.Create(targetPath))
{
var buffer = new byte[bufferSize];
while (true)
{
var count = inputStream.Read(buffer, 0, bufferSize);
if (count > 0)
{
outputStream.Write(buffer, 0, count);
}
if (count < bufferSize) break;
}
}
}
Here is the full solution for Xamarin.Android API 21+:
https://gist.github.com/IlyaLavrov97/a76063a49515764b60d5fba3ebbb2662
Its include updates for files from privite download folders and google disk.
The main part of the solution below:
/// <summary>
/// Main feature. Return actual path for file from uri.
/// </summary>
/// <param name="uri">File's uri</param>
/// <param name="context">Current context</param>
/// <returns>Actual path</returns>
private static string GetActualPathForFile(global::Android.Net.Uri uri, Context context)
{
bool isKitKat = Build.VERSION.SdkInt >= BuildVersionCodes.Kitkat;
if (isKitKat && DocumentsContract.IsDocumentUri(context, 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))
return global::Android.OS.Environment.ExternalStorageDirectory + "/" + split[1];
}
// Google Drive
else if (IsDiskContentUri(uri))
return GetDriveFileAbsolutePath(context, uri);
// DownloadsProvider
else if (IsDownloadsDocument(uri))
{
try
{
string id = DocumentsContract.GetDocumentId(uri);
if (!TextUtils.IsEmpty(id))
{
if (id.StartsWith("raw:"))
return id.Replace("raw:", "");
string[] contentUriPrefixesToTry = new string[]{
"content://downloads/public_downloads",
"content://downloads/my_downloads",
"content://downloads/all_downloads"
};
string path = null;
foreach (string contentUriPrefix in contentUriPrefixesToTry)
{
global::Android.Net.Uri contentUri = ContentUris.WithAppendedId(
global::Android.Net.Uri.Parse(contentUriPrefix), long.Parse(id));
path = GetDataColumn(context, contentUri, null, null);
if (!string.IsNullOrEmpty(path))
return path;
}
// path could not be retrieved using ContentResolver, therefore copy file to accessible cache using streams
string fileName = GetFileName(context, uri);
Java.IO.File cacheDir = GetDocumentCacheDir(context);
Java.IO.File file = GenerateFileName(fileName, cacheDir);
if (file != null)
{
path = file.AbsolutePath;
SaveFileFromUri(context, uri, path);
}
// last try
if (string.IsNullOrEmpty(path))
return global::Android.OS.Environment.ExternalStorageDirectory.ToString() + "/Download/" + GetFileName(context, uri);
return path;
}
}
catch
{
return global::Android.OS.Environment.ExternalStorageDirectory.ToString() + "/Download/" + GetFileName(context, uri);
}
}
// MediaProvider
else if (IsMediaDocument(uri))
{
string docId = DocumentsContract.GetDocumentId(uri);
char[] chars = { ':' };
string[] split = docId.Split(chars);
string type = split[0];
global::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] };
return GetDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".Equals(uri.Scheme, StringComparison.OrdinalIgnoreCase))
{
// Return the remote address
if (IsGooglePhotosUri(uri))
return uri.LastPathSegment;
// Google Disk document .legacy
if (IsDiskLegacyContentUri(uri))
return GetDriveFileAbsolutePath(context, uri);
return GetDataColumn(context, uri, null, null);
}
// File
else if ("file".Equals(uri.Scheme, StringComparison.OrdinalIgnoreCase))
return uri.Path;
return null;
}