question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

.NET MAUI does not work with Android 13 Android.permission.write_external_storage

See original GitHub issue

Description

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

  1. Create a new .NET MAUI App with the default template (not empty template).
  2. Replace the code in the OnCounterClicked method with the code below.
  3. Connect your device to your PC (my device is Google Pixel Pro 6).
  4. Run (Debug) the app on the local Android 13 device.
  5. Click the Counter button
  6. 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:closed
  • Created 10 months ago
  • Reactions:16
  • Comments:75 (29 by maintainers)

github_iconTop GitHub Comments

11reactions
Stedy59commented, Nov 11, 2022

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.

<manifest>
    <!-- Required only if your app targets Android 13. -->
    <!-- Declare one or more the following permissions only if your app needs
    to access data that's protected by them. -->
    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
    <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
    <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />

    <!-- Required to maintain app compatibility. -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
                     android:maxSdkVersion="32" />
    
</manifest>

It is the same for notifications!

<manifest >
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

</manifest>

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

4reactions
Ghostbirdcommented, Jan 23, 2023

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):

  <uses-sdk android:minSdkVersion="21"
    android:targetSdkVersion="32" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" 
    android:maxSdkVersion="32" />

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 the uses-permission is omitted, because we’re at API 33. If I remove the android:maxSdkVersion attribute from the uses-permission line, I still build API 33 according to the warning, but now suddenly uses-permission does 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.

Read more comments on GitHub >

github_iconTop 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 >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found