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.
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
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP