Closed ghost closed 3 years ago
You get this error because you don't have access to /storage/emulated/0/CS500S. To grant access you need to create the storage by user intervention. It is the android policy and you can not do anything about that unless you want to just read and write in a specific folder in SD card that is assigned to your apps which is obtained by context.GetExternalFilesDir(null).
private const int BROWSE_REQUEST_CODE = 100; //Just a unique number
// Select a folder by Intent
private void BrowseOnClick(object sender, EventArgs eventArgs)
{
SafStorageHelper.BrowserFolder(this, BROWSE_REQUEST_CODE);
}
// Access the folder via SafStorgeProvider
protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if (requestCode == BROWSE_REQUEST_CODE && resultCode == Result.Ok)
{
var uri = SafStorageHelper.ResolveFromActivityResult(this, data);
var storage = SafStorgeProvider.CreateStorage(this, uri);
storage.CreateStorage("_PortableStorage.Test");
storage.WriteAllText("test.txt", "123");
}
}
Sorry, for my weird description in the first post.
Please see MainActivity.cs and MainPage.xaml.cs. MainActivity works fine und the BrowserFolder is displayed and I selected the CS500S folder. ReadWriteTest() creates a folder und writes data to it and it can be read.
In MainPage OpenStreamWrite_ByPath() (I took it from your test suite) is called and the temp folder ist created but storage.OpenStreamWrite fires an exception: System.UnauthorizedAccessException Message=Access to the path "/storage/emulated/0/CS500S/_test_portablestroage/d13f0159-44e3-49b4-b04f-d84b55f303c9/filename.txt" is denied.
//** //MainActivity.cs: //**
using System; using Android.App; using Android.Content.PM; using Android.Runtime; using Android.OS; using PortableStorage.Droid; using Android.Content;
namespace HelloXamarin.Droid {
[Activity(Label = "HelloXamarin", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize )]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
private const int BROWSE_REQUEST_CODE = 100;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
// uncomment for test
SafStorageHelper.BrowserFolder(this, BROWSE_REQUEST_CODE);
// uncomment for test
TestReadWrite(this, null);
LoadApplication(new App());
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
private Uri StorageUri
{
get
{
var value = Xamarin.Essentials.Preferences.Get("LastUri", null);
return value != null ? new Uri(value) : null;
}
set
{
Xamarin.Essentials.Preferences.Set("LastUri", value.ToString());
}
}
protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
try
{
if (requestCode == BROWSE_REQUEST_CODE && resultCode == Result.Ok)
StorageUri = SafStorageHelper.ResolveFromActivityResult(this, data);
}
catch (Exception ex)
{
Console.WriteLine("[SAF*******]Error: " + ex.Message);
}
}
private void Browse(object sender, EventArgs eventArgs)
{
SafStorageHelper.BrowserFolder(this, BROWSE_REQUEST_CODE);
}
private void TestReadWrite(object sender, EventArgs eventArgs)
{
try
{
if (StorageUri == null) throw new Exception("No folder has been selected!");
var filename = "test.txt";
var sampleText = "Sample Text";
using var storage = SafStorgeProvider.CreateStorage(this, StorageUri);
var testStorage = storage.CreateStorage("_PortableStorage.Test");
testStorage.WriteAllText(filename, sampleText);
var res = testStorage.ReadAllText(filename);
if (res == sampleText)
{
Console.WriteLine("[SAF*******]Info: The content has been written and readed successfully");
Console.WriteLine("[SAF*******]Now you have a access to the storage even after reloading the App.");
}
else
{
throw new Exception("The sample file content couldn't be readed properly!");
}
}
catch (Exception ex)
{
Console.WriteLine("[SAF*******]Error: " + ex.Message);
}
}
}
}
//** //MainPage.xaml.cs //**
using System; using Xamarin.Forms; using EasyModbus; using System.Threading; using System.IO; using System.Xml.Serialization;
using PortableStorage.Exceptions; using PortableStorage.Providers; using PortableStorage;
namespace HelloXamarin { public partial class MainPage : ContentPage {
public MainPage()
{
InitializeComponent();
OpenStreamWrite_ByPath();
}
private static string StorePath => Path.Combine("/storage/emulated/0/CS500S", "_test_portablestroage");
//private static string StorePath => Path.Combine(Xamarin.Essentials.Preferences.Get("LastUri", null), "_test_portablestroage");
private StorageRoot GetTmpStorage(StorageOptions options = null)
{
var storePath = Path.Combine(StorePath, Guid.NewGuid().ToString());
var storage = FileStorgeProvider.CreateStorage(storePath, true, options);
return storage;
}
public void OpenStreamWrite_ByPath()
{
using var storage = GetTmpStorage();
//check without path
using (var ret = storage.OpenStreamWrite("filename.txt"))
{
if (storage.EntryExists("filename.txt")) Console.WriteLine("[SAF*******]IsTrue:filename.txt");
}
//check with path
using (var ret = storage.OpenStreamWrite("foo1/foo2/foo3/filename2.txt"))
{
var storage2 = storage.OpenStorage("foo1/foo2/foo3");
var e2 = storage2.EntryExists("filename2.txt");
if (!storage.EntryExists("filename2.txt")) Console.WriteLine("[SAF*******]IsFalse: file should not exist in root");
if (storage2.EntryExists("filename2.txt")) Console.WriteLine("[SAF*******]IsTrue: file should exist in path");
}
}
}
}
The following code will never work; you can not create storage by hard coding the path in Android
private static string StorePath => Path.Combine("/storage/emulated/0/CS500S", "_test_portablestroage"); // not work!!
var storage = FileStorgeProvider.CreateStorage(storePath, true, options);
In android you need the base path form this
if (requestCode == BROWSE_REQUEST_CODE && resultCode == Result.Ok)
StorageUri = SafStorageHelper.ResolveFromActivityResult(this, data);
Android doesn't allow you to access a path with hardcoded path like "/storage/emulated/0/CS500S", you need to prompt the user by SafStorageHelper.BrowserFolder then you will have access to the directory and subdirectory which is selected by users. Android doesn't grant access to any directory which is not selected by users.
Hi madnik7,
I try to integrate you PortableStorage package in my Xamarin.Forms application. I use VS2019 V16.11.2 the test device is a Samsung tablet with Android 11.
In MainActivity.cs
In MainPage.cs I used the CopyTo() example from your Test suite:
With the private static string StorePath => Path.Combine("/storage/emulated/0/CS500S", "_test_portablestroage"); the destStorage and rootStorage folders are created, but then WriteAllText fires an exception: System.UnauthorizedAccessException Message=Access to the path "/storage/emulated/0/CS500S/_test_portablestroage/09d85dc8-dc26-45ee-8d80-a0ee1d2705d1/foo1/filename1.txt" is denied.
When I use private static string StorePath => Path.Combine(Xamarin.Essentials.Preferences.Get("LastUri", null), "_test_portablestroage"); an exception: System.IO.IOException Message=Read-only file system is fired in var storage = FileStorgeProvider.CreateStorage(storePath, true, options); and no folder is created.
Can you help? Best regards Horst