Search code examples
androidfilexamarinpermissions

Permission Denied when writing file on internal storage from Xamarin


I'm trying to do the following:

        var photo = await MediaPicker.CapturePhotoAsync();
        string maindir = Path.Combine(Xamarin.Essentials.FileSystem.AppDataDirectory, "Pictures");
        string filename = System.DateTime.Now.ToString("yyyyMMdd_HHmmss") + System.IO.Path.GetExtension(photo.FileName);
        var newFile = Path.Combine(maindir, filename);
        Directory.CreateDirectory(newFile);
        using (var stream = await photo.OpenReadAsync())
        {
            using (var newStream = File.OpenWrite(newFile))
            {
                await stream.CopyToAsync(newStream);
            }
        }

By using Xamarin.Essentials.FileSystem.AppDataDirectory, I should be getting a folder within the internal storage (incidentally, I also provided external storage writing permissions, but that should not be relevant - and it didn't resolve the issue). The rest of the code is near verbatim from Xamarin.Essentials documentation.

On the line with File.OpenWrite, I get an UnauthorizedAccessException, saying "Access to the path '/data/user/0/com.companyname.peerpeek/files/Pictures/20231115_154707.jpg' is denied".

From everything I've read, this should not be happening. So: is this a bug or am I missing something obvious here?

For good measure: I get this error both when running it on an emulated Pixel 5 (Android 13) and when I debug on my own Phone (Android 12).

[Edit] As requested: here's the full Exception:

System.UnauthorizedAccessException: Access to the path '/data/user/0/com.companyname.peerpeek/files/Pictures/20231115_163542.jpg' is denied.
  at System.IO.FileStream..ctor (System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share, System.Int32 bufferSize, System.Boolean anonymous, System.IO.FileOptions options) [0x000e7] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/corlib/System.IO/FileStream.cs:196 
  at System.IO.FileStream..ctor (System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share) [0x00000] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/corlib/System.IO/FileStream.cs:91 
  at (wrapper remoting-invoke-with-check) System.IO.FileStream..ctor(string,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare)
  at System.IO.File.OpenWrite (System.String path) [0x00000] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/external/corefx/src/System.IO.FileSystem/src/System/IO/File.cs:271 
  at PeerPeek.MainPage.LoadPhotoAsync (Xamarin.Essentials.FileResult photo) [0x00187] in C:\Users
icksa\source\repos\PeerPeek\PeerPeek\PeerPeek\MainPage.xaml.cs:88

Solution

  • Directory.CreateDirectory(newFile);

    That should be:

    Directory.CreateDirectory(mainDir); 
    

    Now the file cannot be created because there is already a directory with the same name.

    Indeed action denied.