dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
21.98k stars 1.72k forks source link

UnauthorizedAccessException while accessing file using FileStream in Android #24346

Open MohanaselvamJ opened 3 weeks ago

MohanaselvamJ commented 3 weeks ago

Description

When opening file that exist in Download folder of Android device, it throws System.UnauthorizedAccessException: 'Access to the path '/storage/emulated/0/Download/HelloWorld/docx' is denied'

Steps to Reproduce

  1. Create a MAUI app.
  2. Add the below code in Platforms->Android-> SaveFile

`

string externalPath = Android.OS.Environment.ExternalStorageDirectory.Path;
                string folder = "/Download/";
                string relativePathInput = externalPath + folder + "HelloWorld.docx";
                string relativePathOutput = externalPath + folder + "HelloWorld_RelativeOpenSave.docx";

                //Not works
                using (FileStream sourceStream = new FileStream(relativePathInput, FileMode.Open, FileAccess.ReadWrite))
                {
                    using (FileStream destStream = new FileStream(relativePathOutput, FileMode.Create, FileAccess.ReadWrite))
                    {
                        sourceStream.Position = 0;
                        sourceStream.CopyTo(destStream);
                    }
                }

`

  1. Call this code from "MainPage.xaml.cs"

  2. In the android device, maintain a file "HelloWorld.docx" inside Download folder.

  3. Build and deploy the app in Android device.

  4. Checked whether file existing using below code examples, both return true only Java.IO.File file = new Java.IO.File(folderPath + filename); if (file.Exists())

Another way: bool isExist = File.Exists(folderPath + filename);

Note: This issue not occurs while writing a file using same path and below code. So, issue in opening only

using (FileStream destStream = new FileStream(relativePathOutput, FileMode.Create, FileAccess.ReadWrite))

Link to public reproduction project repository

No response

Version with bug

8.0.80 SR8

Is this a regression from previous behavior?

Not sure, did not test other versions

Last version that worked well

Unknown/Other

Affected platforms

Android

Affected platform versions

Android 10.0

Did you find any workaround?

Suggestion tried:

  1. Added permission in manifest file
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application android:allowBackup="true" android:icon="@mipmap/appicon" android:supportsRtl="true">
        <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true">
            <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" />
        </provider>
    </application>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
    </manifest>

Relevant log output

System.UnauthorizedAccessException: 'Access to the path '/storage/emulated/0/Download/HelloWorld/docx' is denied'
github-actions[bot] commented 3 weeks ago

Hi I'm an AI powered bot that finds similar issues based off the issue title.

Please view the issues below to see if they solve your problem, and if the issue describes your problem please consider closing this one and thumbs upping the other issue to help us prioritize it. Thank you!

Open similar issues:

Closed similar issues:

Note: You can give me feedback by thumbs upping or thumbs downing this comment.

tompi commented 2 weeks ago

Hey, Im no expert, but Im pretty sure Android 10 changed the way you can access files external to the application. https://developer.android.com/about/versions/10/privacy/changes#scoped-storage

More info here: https://stackoverflow.com/questions/60415859/is-it-possible-to-programmatically-access-download-folder-on-android-q-sdk-2

I think the recommended way is to use FileSystem.AppDataDirectory or FileSystem.CacheDirectory to work with files. (thats what I do, and works fine)

If you need to open external folders, I think you need to gain explicit permission from the user, using the DocumentsProvider (which I had to do once, and will avoid in the future, its clunky and not user friendly...) https://developer.android.com/reference/android/provider/DocumentsProvider.html

MohanaselvamJ commented 2 weeks ago

@tompi

Thanks for your suggestion. I have tried below things but not works

  1. FileSystem.AppDataDirectory & FileSystem.CacheDirectory , these are accessing data/user/0/com../ folder. But, they are not visible in Mobile to maintain input documents there.
  2. Tried by adding below permission in Manifest file, but not works. <uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />

End requirement: We need to access document from mobile storage using FileStream overload

tompi commented 2 weeks ago

FileStream works fine with appdata and cachedirectory, but if you need to store these files so that users can access them outside the app, you need to let user explicitly select the folder where you will store the file, using scoped storage:

https://source.android.com/docs/core/storage/scoped

In android 10, it is possible to opt out of this new model, using legacy storage mode, but its just temporary and wont work in android 11+: https://developer.android.com/reference/android/R.attr#requestLegacyExternalStorage