Google Resolved: UnauthorizedAccessException for write or read file in Xamarin.Forms Android (C# - Xaml) | SubramanyamRaju Xamarin & Windows App Dev Tutorials

Friday 13 December 2019

Resolved: UnauthorizedAccessException for write or read file in Xamarin.Forms Android (C# - Xaml)

Introduction:

Android considers accessing external storage to be a dangerous permission, which typically requires the user to grant their permission to access the resource. The user may revoke this permission at any time. This means that a run time permission request should be performed prior to any file access. Apps are automatically granted permissions to read and write their own private files. It is possible for apps to read and write the private files that belong to other apps after being granted permission by the user.

Description:

Permission Model before M (API 23): Before API 23, the permission model was simpler to the developer but offered less control and security to the user – requested permissions are presented to the user before installing the application. The user needs to decide whether to give these permissions to the application and install it or to deny as a whole and don’t install the application. Permissions cannot be denied or granted after the installation. Thus developers were required only to declare all needed permissions in the manifest and then just forget; if the app is running then it has all the requested permissions.
Permission Model from M (API 23): With Android 6.0 Marshmallow (API 23), a new runtime permission model has been introduced. According to this model users are not prompted for permission at the time of installing the app, rather developers need to check for and request permission at runtime (i.e. before performing any action that may require the particular permission), users can then allow or deny the permission, users can also grant or revoke permission anytime from settings. Making the user experience very secure on an Android device. But inversely this feature imposes a great deal of effort on development. Therefore developers have to handle all the use cases.

So in xamarin from Android SDK API 23, if you are not request permission at runtime when write/read file files from external storage. You will get below exception
"System.UnauthorizedAccessException: Access to the path "/storage/emulated/0/1.pdf" is denied.

So to resolve above error, please follow below steps in your xamarin.forms project

Step 1:
All Android apps must declare one of the two permissions for external storage in the AndroidManifest.xml . To identify the permissions, one of the following two uses-permission elements must be add to AndroidManifest.xml:
  • <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />  
  • <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  
  • Step 2:
    Open MainActivity.cs in your android project and add below method
    1. public bool CheckAppPermissions()  
    2.         {  
    3.             if ((int)Build.VERSION.SdkInt < 23)  
    4.             {  
    5.                 return true;  
    6.             }  
    7.   
    8.             if (!(ContextCompat.CheckSelfPermission(this, Manifest.Permission.WriteExternalStorage) == (int)Permission.Granted) && !(ContextCompat.CheckSelfPermission(this, Manifest.Permission.ReadExternalStorage) == (int)Permission.Granted))  
    9.             {  
    10.                 var permissions = new string[] { Manifest.Permission.ReadExternalStorage, Manifest.Permission.WriteExternalStorage };  
    11.                 ActivityCompat.RequestPermissions(this, permissions, REQUEST_FOLDER_PERMISSION);  
    12.                 return false;  
    13.             }  
    14.             return true;  
    15.   
    16.         }  

    Step 3:
    Create below interface in shared project

    1. public interface ICheckFilePermission  
    2.     {  
    3.         bool CheckPermission();  
    4.     }  

    Step 4:
    In App.xaml.cs, add below static property
    1. public static object ParentWindow { getset; }  
    Step 5:In MainActivity.cs, 
    1. protected override void OnCreate(Bundle bundle)  
    2.         {  
    3.   
    4.             base.OnCreate(bundle);  
    5.   
    6.             global::Xamarin.Forms.Forms.Init(this, bundle);  
    7.             LoadApplication(new App());  
    8.   
    9.             App.ParentWindow = this;             
    10.         }  
    Step 6:
    In your android project, add below below code

    1. [assembly: Dependency(typeof(CheckFilePermission))]  
    2. namespace MPermissions.Droid.PlatformSpecifics  
    3. {  
    4.     public class CheckFilePermission : ICheckFilePermission  
    5.     {  
    6.         MainActivity mainActivity;  
    7.   
    8.         public bool CheckPermission()  
    9.         {  
    10.             mainActivity = (BCP2GO.Droid.MainActivity)App.ParentWindow;  
    11.             if (mainActivity.CheckAppPermissions())  
    12.             {  
    13.                 return true;  
    14.             }  
    15.             else  
    16.             {  
    17.                 return false;  
    18.             }  
    19.         }  
    20.     }  
    21. }  

    Step 7:
    Finally invoke file permission request like below:
  • if (DeviceInfo.Platform.ToString() == Device.Android)  
  •             {  
  •                 DependencyService.Get<ICheckFilePermission>().CheckPermission();  
  •             }  

  • FeedBack Note: Please share your thoughts, what you think about this post, Is this post really helpful for you? I always welcome if you drop comments on this post and it would be impressive.


    Follow me always at @Subramanyam_B

    6 comments:

    1. What does REQUEST_FOLDER_PERMISSION stand for or mean?

      ReplyDelete
    2. Hello Subramanyam Raju, thanks for sharing this code, but I really know it in Xamarin. Can I download a functional example somewhere? I still can't configure WRITE_EXTERNAL_STORAGE. I have been working several days without finding the solution. Thank you.


      ReplyDelete
    3. same problem. I can't write on root SD card directory

      ReplyDelete
    4. Why you store current Activity (MainActivity) in Netstandart lib instread store in insiade Android project

      mainActivity = (BCP2GO.Droid.MainActivity)App.ParentWindow;

      ????

      May be better store int inside like ^


      public static Context myMainActivity;

      protected override void OnCreate(Bundle savedInstanceState)
      {
      myMainActivity = this;

      ........
      }

      ReplyDelete
    5. CheckAppPermissions() Add to MainActivity.OnCreate() Step 3 can be skipped. REQUEST_FOLDER_PERMISSION I entered 777, which can be used

      ReplyDelete

    Search Engine Submission - AddMe