.NET MAUI does not work with Android 13 Android.permission.write_external_storage
See original GitHub issueDescription
My App was working and able to take pictures on Android 12 and .NET 6 but as soon as I upgraded to Android 13 and .NET 7, it stopped working. When I call this method:
FileResult photo = await MediaPicker.Default.CapturePhotoAsync();
I get this error: Microsoft.Maui.ApplicationModel.PermissionException: ‘StorageWrite permission was not granted: Denied’.
I do have these declarations in the AndroidManifest.xml file:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<queries>
<intent>
<action android:name="android.media.action.IMAGE_CAPTURE" />
</intent>
</queries>
Steps to Reproduce
- Create a new .NET MAUI App with the default template (not empty template).
- Replace the code in the OnCounterClicked method with the code below.
- Connect your device to your PC (my device is Google Pixel Pro 6).
- Run (Debug) the app on the local Android 13 device.
- Click the Counter button
- Notice the error
Link to public reproduction project repository
https://github.com/FatCodeMonkey/MAUIPhoto
Version with bug
6.0.486 (current)
Last version that worked well
6.0.424
Affected platforms
Android
Affected platform versions
Android 13
Did you find any workaround?
No
Relevant log output
0xFFFFFFFFFFFFFFFF in Android.Runtime.JNIEnv.monodroid_debugger_unhandled_exception C#
0x1A in Android.Runtime.JNINativeWrapper._unhandled_exception at /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs:12,5 C#
0x1D in Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PP_V at /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs:23,26 C#
0x17 in System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw C#
0x6 in System.Threading.Tasks.Task.<>c.<ThrowAsync>b__128_0 C#
0xC in Android.App.SyncContext. at /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.App/SyncContext.cs:36,19 C#
0xE in Java.Lang.Thread.RunnableImplementor.Run at /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Java.Lang/Thread.cs:36,6 C#
0x8 in Java.Lang.IRunnableInvoker.n_Run at /Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/net6.0/android-33/mcw/Java.Lang.IRunnable.cs:84,4 C#
0x8 in Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PP_V at /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs:22,5 C#
Issue Analytics
- State:
- Created 10 months ago
- Reactions:16
- Comments:75 (29 by maintainers)
Top Results From Across the Web
Android 13 - How to request WRITE_EXTERNAL_STORAGE
The WRITE_EXTERNAL_STORAGE permission seems to be working fine below API 33 i.e. Android 12 and less but the runtime permission popup for ...
Read more >Manage Write External Storage Permission android 13
This is the video about manage Write External Storage Permission android 13 | Android 13 Storage Permission Capture Image from Camera ...
Read more >Permissions - .NET MAUI
Learn how to use the .NET MAUI Permissions class, to check and request permissions. This class is in the Microsoft.Maui.
Read more >Behavior changes: Apps targeting Android 13 or higher
Learn about changes in Android 13 that will affect apps when they target Android 13 or higher.
Read more >How to Save a File in Shared Storage Location in Android 13
1. Read/Write files in App-Specific Private Storage Locations · Internal Storage — The phone's Internal Storage, can only be accessed by App. ·...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found

What baffles me, is that .net MAUI was released with an initial target Android API of 33. But the underlying code does not support Android API 33!
Starting from Android 13, if your application target SDK is specified to 33 or above, the READ_EXTERNAL_STORAGE permission will be completely useless, and applying for it will have no effect.
Correspondingly, Google has added three runtime permissions: READ_MEDIA_IMAGES, READ_MEDIA_VIDEO, and READ_MEDIA_AUDIO, which are used to manage the photos, videos and audio files of the phone respectively. That is to say, in the past, you only needed to apply for a READ_EXTERNAL_STORAGE permission. This is no longer possible. You have to apply for it on demand, so that users can learn more precisely which media permissions your app has applied for.
It is the same for notifications!
I pulled the Android permissions code, and updated it to support API 33. Hopefully they will realize that making the “Essentials” an actual part of the MAUI core, requires a higher level of attention to external API changes.
@PureWeen @UkeHa
Ok, I managed to find it, and it has to do with a really unexpected twist in how certain values in the android manifest are applied.
I followed this thread, and applied appropriate changes to the manifest, such as the relevant parts of this comment and this comment.
Therefore my android manifest ended up with these two lines (other lines omitted):
This seems correct. I want to build with support for API 21 - 32, and on all those API versions WRITE_EXTERNAL_STORAGE exists, is required, and is requested. If I ever upgrade to building for API 33, WRITE_EXTERNAL_STORAGE should not be requested for that API 33 version, because it doesn’t exist in API 33.
In this case I set
android:targetSdkVersion="32", and I get the warning that it compiles with API 33 after all. Apparently this means that theuses-permissionis omitted, because we’re at API 33. If I remove theandroid:maxSdkVersionattribute from theuses-permissionline, I still build API 33 according to the warning, but now suddenlyuses-permissiondoes work correctly, even though that permission doesn’t even exist in API 33.I’m baffled, yet happy that our release-blocker can be bypassed this way.