Проблема с "DownloadFile", не работающим в Android (версия 10) даже после получения разрешений для приложения - PullRequest
0 голосов
/ 04 августа 2020

Я новичок (как на двух курсах Udemy C# и паре видеороликов с кодом игры ti c ta c toe & snake на YouTube для начинающих, поэтому, пожалуйста, извините за мое незнание) с помощью Visual Studio 19 и Xamarin для Android, чтобы создать приложение-парсер для моего телефона Android. Основная проблема, с которой я столкнулся, заключается в том, что когда я использую метод WebClient DownloadFile, я получаю «System. Net .WebException» (System.UnauthorizedAccessException) со словами «Доступ к пути [имя файла] запрещен».

Я нашел несколько других сообщений в стеке с похожими проблемами, и все они сказали, что проблема не в проверке / предоставлении разрешений, но даже после добавления кода для запроса / предоставления разрешения я получу такое же исключение. Возможно, я добавил код неправильно, но я так не думал, поскольку, когда я тестировал его на эмуляторе, всплывающее окно с разрешениями, казалось, работало. Вот исключение:

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

Вот мой код для загрузки видео с 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);
            }

        }

Я всегда получаю исключение в строке downloadClient.DownloadFile(fullLink, file);.

Я также пробовал использовать MediaStore, но, честно говоря, я толком не понимал, как это и как работает контекст.

Вот разрешения, которые я добавил в 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" />

И вот код OnCreate:

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);
            };

        }

Раньше я использовал код разрешений проверки по-другому (как видно в закомментированном коде) и изначально имел его, как показано в видеоуроке в Android документация для разработчиков , но в конце концов решил оставить как есть.

Любая помощь будет принята с благодарностью, и я постараюсь ответить на любые вопросы, которые могу. Я просмотрел много документации, но иногда мне кажется, что лучше обратиться за помощью к кому-нибудь более опытному, чем я.

Ответы [ 2 ]

0 голосов
/ 04 августа 2020

Начните с Android 6.0, Android требуются разрешения времени выполнения. И когда вы хотите загрузить файл, вам потребуется разрешение на хранение.

Я делаю пример кода о том, как загрузить по ссылке с помощью предоставленного вами метода DownloadVideo. Поскольку у меня нет ссылки на видео, я использую ссылку для загрузки изображения для справки.

  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);
        }
    }

}
0 голосов
/ 04 августа 2020

На Android 10 / Q используемый путь недоступен. Об этом сообщалось здесь сотни раз.

Вы все еще можете получить доступ, добавив legacyExternalStorage true в файл манифеста. Это вы также можете сто раз прочитать в stackoverflow.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...