Forum Cross Platform with Xamarin

Xamarin.Essentials.FilePicker returns Uri (How to get path or byte[] from picked file)

I can able to get proper path using iOS simulator but it is not happening in Android simulator where I retrieved URI instead of normal path.
The path retrieved is "content://com.android.providers.downloads.documents/document/22".

How to get proper path in my cross platform project using Android Emulator or Device?

Best Answer

  • YelinzhYelinzh Member, Xamarin Team Xamurai
    edited January 26 Accepted Answer

    Hi, Harshitha_Uday. The path of the picked file may contain a content URI that starts with content://, try to check if the FullPath's value starts with content:// and then convert the uri to actual path on native Android using DependencyService.

    Check the code:

    [assembly: Dependency(typeof(GetActualPath))]
    namespace TestApplication_2.Droid
    {
        public class GetActualPath : IGetActualPath
        {
            public string GetActualPathFromFile(string thePathUri)
            {
                Android.Net.Uri uri = Android.Net.Uri.Parse(thePathUri);
    
                bool isKitKat = Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Kitkat;
                if (isKitKat && DocumentsContract.IsDocumentUri(Android.App.Application.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 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(Android.App.Application.Context, 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(Android.App.Application.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;
    
                    return getDataColumn(Android.App.Application.Context, 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);
            }
        }
    }
    

    Refer to: https://stackoverflow.com/questions/46975574/how-to-get-actual-path-from-uri-xamarin-android


    Xamarin forums are migrating to a new home on Microsoft Q&A!
    We invite you to post new questions in the Xamarin forums’ new home on Microsoft Q&A!
    For more information, please refer to this sticky post.

Answers

  • YelinzhYelinzh Member, Xamarin Team Xamurai
    edited January 25

    Hi, the FilePicker.PickAsync method returns a result that is type of FileResult. The FileResult class provides the FullPath property which could help to get the full path and filename, try using the property to get the path.

    Check the code:

    private async void Button_Clicked(object sender, EventArgs e)
    {
        var result = await FilePicker.PickAsync();
        var path = result.FullPath;
    }
    

    Xamarin forums are migrating to a new home on Microsoft Q&A!
    We invite you to post new questions in the Xamarin forums’ new home on Microsoft Q&A!
    For more information, please refer to this sticky post.

  • Harshitha_UdayHarshitha_Uday Member ✭✭

    Thank you. I am using the same code but full path returned in Android Emulator is URI but I am expecting an absolute path like file in download has /storage/emulated/0/Downloads/ this path. I am unable to find picked file in this location content://com.android.providers.downloads.documents/document/22. Please find my code below.

    public async void addFile_Clicked(object sender, EventArgs e)
    {
    var customFileType =
    new FilePickerFileType(new Dictionary<DevicePlatform, IEnumerable>
    {
    { DevicePlatform.Android, new[]{"/"} },
    {DevicePlatform.iOS, new[] {"com.adobe.pdf", "public.image", "public.movie"} }
    });

            file = await FilePicker.PickAsync(new PickOptions
    
            {
                FileTypes = customFileType,
                PickerTitle = "Pick an Image"
            });
    
            if (file != null)
            {
                lblFileName.Text = file.FileName;
                filePath = file.FullPath; // o/p: content://com.android.providers.downloads.documents/document/22
    
        }
    
  • YelinzhYelinzh Member, Xamarin Team Xamurai

    I tested the posted code, it also works fine. What's version of the package in your project? Try to update the Xamarin.Forms pakcage and Xamarin.Essentials to the lastest stable version and test again.


    Xamarin forums are migrating to a new home on Microsoft Q&A!
    We invite you to post new questions in the Xamarin forums’ new home on Microsoft Q&A!
    For more information, please refer to this sticky post.

  • Harshitha_UdayHarshitha_Uday Member ✭✭

    Yeah package is also up to date. It is working fine but i want real path of the picked file not this content://com.android.providers.downloads.documents/document/22. Because I should upload my file to AWS S3.

    In iOS the path retrieved is exact path where the file is located. Can you please help me to get exact file path of the picked file.

  • YelinzhYelinzh Member, Xamarin Team Xamurai
    edited January 26 Accepted Answer

    Hi, Harshitha_Uday. The path of the picked file may contain a content URI that starts with content://, try to check if the FullPath's value starts with content:// and then convert the uri to actual path on native Android using DependencyService.

    Check the code:

    [assembly: Dependency(typeof(GetActualPath))]
    namespace TestApplication_2.Droid
    {
        public class GetActualPath : IGetActualPath
        {
            public string GetActualPathFromFile(string thePathUri)
            {
                Android.Net.Uri uri = Android.Net.Uri.Parse(thePathUri);
    
                bool isKitKat = Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Kitkat;
                if (isKitKat && DocumentsContract.IsDocumentUri(Android.App.Application.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 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(Android.App.Application.Context, 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(Android.App.Application.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;
    
                    return getDataColumn(Android.App.Application.Context, 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);
            }
        }
    }
    

    Refer to: https://stackoverflow.com/questions/46975574/how-to-get-actual-path-from-uri-xamarin-android


    Xamarin forums are migrating to a new home on Microsoft Q&A!
    We invite you to post new questions in the Xamarin forums’ new home on Microsoft Q&A!
    For more information, please refer to this sticky post.

  • Harshitha_UdayHarshitha_Uday Member ✭✭

    Yeah Thanks. I am able to get picked files actual path except from Downloads location.

    I got an exception **java.lang.IllegalArgumentException: Unknown URI: content://downloads/public_downloads/**** when I tried with this content://downloads/public_downloads

    Then I changed to content://downloads/my_downloads"
    The file picked from Downloads is returning null as actual path.

    I don't know what is happening at this point. Please help me to fix this.

  • YelinzhYelinzh Member, Xamarin Team Xamurai

    I got an exception **java.lang.IllegalArgumentException: Unknown URI: content://downloads/public_downloads/****

    Try to detect the Android build version to check if it is greater than 8.0, use the URI returned by the file selector directly.

    else if (isDownloadsDocument(uri))
    {
        string id = DocumentsContract.GetDocumentId(uri);
        Android.Net.Uri contentUri;
    
        if (Build.VERSION.SdkInt < Android.OS.BuildVersionCodes.O)
        {
            contentUri = ContentUris.WithAppendedId(Android.Net.Uri.Parse("content://downloads/public_downloads"), long.Parse(id));
            return getDataColumn(Android.App.Application.Context, contentUri, null, null);
        }
        return getDataColumn(Android.App.Application.Context, uri, null, null);
    }
    
  • Harshitha_UdayHarshitha_Uday Member ✭✭

    I tried above code. There is no exception caught but also failed to get actual path. I found the path as null itself.

  • Harshitha_UdayHarshitha_Uday Member ✭✭

    Hello Yelinzh,

    Thanks for helping me to proceed further. I found solution using the below link where I can get actual path from downloads.

    https://gist.github.com/IlyaLavrov97/a76063a49515764b60d5fba3ebbb2662

  • YelinzhYelinzh Member, Xamarin Team Xamurai

    @Harshitha_Uday Congrats! And please accept the solution as the answer, it'll help others who face the similar problem.

Sign In or Register to comment.