TransWikia.com

Having issue with "DownloadFile" not working in Android (version 10) even after getting app permissions

Stack Overflow Asked by very_human on August 22, 2020

I’m a beginner (as in two Udemy C# courses and a couple of tic tac toe & snake game code-along videos on YouTube beginner, so please excuse my ignorance) using Visual Studio 19 and Xamarin for Android to create a web scraper app for my Android phone. The main issue I’ve been having is when I use the WebClient DownloadFile method I get a "System.Net.WebException"(System.UnauthorizedAccessException) saying "Access to the path [filename] is denied."

I found a few other stack posts with similar issues and they all said the issue was not checking/granting permissions but even after adding code to request/grant permission I would get the same exception. I may have added the code incorrectly but i didn’t think so since when i tested it on an emulator the permissions pop-up seemed to work. Here’s the Exception:

"Access to the path "/storage/emulated/0/Download/6855288302363331845.mp4" is denied."

Here’s my code for downloading the video from the URI:

public static void DownloadVideo(string htmlCode)
        {
            string fullID = GetVideoID(htmlCode);
            string fullLink = GetVideoLink(htmlCode);

            //android filepath (or is it?)
            string directory = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath, Android.OS.Environment.DirectoryDownloads);
            string file = Path.Combine(directory, fullID + ".mp4");

            //download video
            using (WebClient downloadClient = new WebClient())
            {
                downloadClient.DownloadFile(fullLink, file);
            }

        }

I always get the exception on the downloadClient.DownloadFile(fullLink, file); line.

I also tried using MediaStore but honestly I didn’t really understand how that and the context stuff worked.

Here are the permissions I added to the AndroidManifest.xml:

<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

And here’s the OnCreate code:

protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
            Xamarin.Essentials.Platform.Init(this, savedInstanceState);
            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.activity_main);

            

            //get ui controls
            EditText videoUrl = FindViewById<EditText>(Resource.Id.urlInput);
            Button processButton = FindViewById<Button>(Resource.Id.button1);
            Button dlButton = FindViewById<Button>(Resource.Id.button3);
            Button rsButton = FindViewById<Button>(Resource.Id.button2);
            Button permissions = FindViewById<Button>(Resource.Id.button4);
            TextView confirmation = FindViewById<TextView>(Resource.Id.textConfirmation);
            EditText videoID = FindViewById<EditText>(Resource.Id.editText1);
            EditText videoLink = FindViewById<EditText>(Resource.Id.editText2);

            
            //process
            processButton.Click += (sender, e) =>
            {
                string startingUrl = videoUrl.Text.ToString();
                string htmlCode = "";

                if (startingUrl.Contains("tiktok") != true)
                {
                    Core.UrlDownloadAction.UpdateLabel(confirmation, "Invalid Link");
                }
                else
                {
                    htmlCode = Core.UrlDownloadAction.DownloadHTML(startingUrl);

                    videoID.Text = Core.UrlDownloadAction.GetVideoID(htmlCode);
                    videoLink.Text = Core.UrlDownloadAction.GetVideoLink(htmlCode);
                    confirmation.Text = "Successfully Processed";
                    
                }
                

            };

            //download
            dlButton.Click += (sender, e) =>
            {
                string startingUrl = videoUrl.Text.ToString();
                string fullVideoID = videoID.Text.ToString();
                string htmlCode = Core.UrlDownloadAction.DownloadHTML(startingUrl);

                
                
                //download video
                if (startingUrl.Contains("tiktok") != true)
                {
                    Core.UrlDownloadAction.UpdateLabel(confirmation, "Invalid Link");
                }
                else
                {
                    //check & request permissions
                    if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.WriteExternalStorage) != (int)Permission.Granted)
                    {
                        RequestPermissions(new string[] { Manifest.Permission.WriteExternalStorage }, 257);
                    }
                    if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.ReadExternalStorage) != (int)Permission.Granted)
                    {
                        RequestPermissions(new string[] { Manifest.Permission.ReadExternalStorage }, 256);
                    }
                    //download
                    if (htmlCode == "failed")
                    {
                        confirmation.Text = "Invalid HTML";
                    }
                    else
                    {
                        Core.UrlDownloadAction.DownloadVideo(htmlCode);
                        confirmation.Text = "Successful Download";
                    }
                }

                /*if (!(ContextCompat.CheckSelfPermission(this, Manifest.Permission.ReadExternalStorage) == Permission.Granted)*//* && !(ContextCompat.CheckSelfPermission(this, Manifest.Permission.WriteExternalStorage) == Permission.Granted)*//*)
                {
                    if ((ShouldShowRequestPermissionRationale(Manifest.Permission.ReadExternalStorage)))*//* && (ShouldShowRequestPermissionRationale(Manifest.Permission.WriteExternalStorage)))*//*
                    {
                        Toast.MakeText(this, "Storage permissions are needed to save the file.", ToastLength.Short).Show();
                    }
                    //reqest read/write permissions
                    RequestPermissions(new string[] { Manifest.Permission.ReadExternalStorage }, requestCode: 256);
                    RequestPermissions(new string[] { Manifest.Permission.WriteExternalStorage }, requestCode: 257);
                }
                else
                {
                    
                }*/

            };
            
            rsButton.Click += (sender, e) =>
            {
                Core.UrlDownloadAction.ResetDownloader(videoUrl, confirmation, videoID, videoLink);
            };

        }

I used to have the check permissions code implemented differently (as seen in the commented out code) and originally had it as shown in the video tutorial in the Android developers documentation but eventually decided to leave it as is.

Any help would be appreciated and I’ll try to answer any questions I can. I’ve gone through a lot of documentation but sometimes I think it’s better to get help from someone more experienced than myself.

2 Answers

Start with Android 6.0, Android needs runtime permissions. And when you want to download the file, the Storage permission are needed.

I make the code sample about how to download form the link with the DownloadVideo method you provided. Due to i do not have the video link, i use a image downloading link for reference.

  public class Activity_layout1 : Activity
{

    public string TAG
    {
        get
        {
            return "Activity1";
        }
    }
    static readonly int REQUEST_STORAGES = 1;
    static string[] PERMISSIONS_STORAGES = {
    Manifest.Permission.ReadExternalStorage,
    Manifest.Permission.WriteExternalStorage
};

    View layout;
    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);

        // Create your application here

        SetContentView(Resource.Layout.layout1);

        var Request_Permission = FindViewById<Button>(Resource.Id.btn_RequestPermission);
        Request_Permission.Click += delegate
        {
            Log.Info(TAG, "Show Storage button pressed. Checking permissions.");

            // Verify that all required contact permissions have been granted.
            if (ActivityCompat.CheckSelfPermission(this, Manifest.Permission.ReadExternalStorage) != (int)Permission.Granted
                || ActivityCompat.CheckSelfPermission(this, Manifest.Permission.WriteExternalStorage) != (int)Permission.Granted)
            {
                // Contacts permissions have not been granted.
                Log.Info(TAG, "Storage permissions has NOT been granted. Requesting permissions.");
                RequestContactsPermissions();
            }
            else
            {
                // Contact permissions have been granted. Show the contacts fragment.
                Log.Info(TAG, "Storage permissions have already been granted.");

            }
        };

        var Download = FindViewById<Button>(Resource.Id.btn_Download);
        Download.Click += delegate
        {

            //android filepath (or is it?)
            string directory = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath, Android.OS.Environment.DirectoryDownloads);
            string file = Path.Combine(directory, "abc" + ".jpg");

            //download video
            using (WebClient downloadClient = new WebClient())
            {
                downloadClient.DownloadFile("http://www.dada-data.net/uploads/image/hausmann_abcd.jpg", file);
            }

        };

        var Check = FindViewById<Button>(Resource.Id.btn_CheckFile);
        Check.Click += delegate
        {
            string directory = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath, Android.OS.Environment.DirectoryDownloads);
            string file = Path.Combine(directory, "abc" + ".jpg");
            if (File.Exists(file))
            {
                Android.App.AlertDialog.Builder dialog = new AlertDialog.Builder(this);
                AlertDialog alert = dialog.Create();
                alert.SetTitle("File Check");
                alert.SetMessage("File Exists!!!");
                alert.SetButton("OK", (c, ev) =>
                {
                    // Ok button click task  
                });
                alert.Show();
            }
        };
    }

    void RequestContactsPermissions()
    {
        if (ActivityCompat.ShouldShowRequestPermissionRationale(this, Manifest.Permission.ReadContacts)
            || ActivityCompat.ShouldShowRequestPermissionRationale(this, Manifest.Permission.WriteContacts))
        {
            Log.Info(TAG, "Displaying storage permission rationale to provide additional context.");

            // Display a SnackBar with an explanation and a button to trigger the request.
            Snackbar.Make(layout, "Storage Permission is needed",
                Snackbar.LengthIndefinite).SetAction("OK", new Action<View>(delegate (View obj)
                {
                    ActivityCompat.RequestPermissions(this, PERMISSIONS_STORAGES, REQUEST_STORAGES);
                })).Show();
        }
        else
        {
            //  permissions have not been granted yet. Request them directly.
            ActivityCompat.RequestPermissions(this, PERMISSIONS_STORAGES, REQUEST_STORAGES);
        }
    }
    public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Permission[] grantResults)
    {
        if (requestCode == REQUEST_STORAGES)
        {
            // Received permission result for  permission.
            Log.Info(TAG, "Received response for Storage permission request.");

            // Check if the only required permission has been granted
            if ((grantResults.Length == 1) && (grantResults[0] == Permission.Granted))
            {
                Log.Info(TAG, "Storage permission has now been granted.");
            }
            else
            {
                Log.Info(TAG, "Storage permission was NOT granted.");
            }
        }
        else
        {
            base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

}

Answered by Wendy Zang - MSFT on August 22, 2020

On Android 10/Q the used path is not accessable. This has been reported here a hundred times.

You can still get access by adding legacyExternalStorage true to manifest file. This you can also read a hundred times on stackoverflow.

Answered by blackapps on August 22, 2020

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP