Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
FatCodeMonkey opened this issue Nov 11, 2022 · 75 comments · Fixed by #12766
Closed
Labels
fixed-in-7.0.81 Look for this fix in 7.0.81! fixed-in-7.0.100 fixed-in-7.0.101 fixed-in-8.0.0-preview.1.7762 Look for this fix in 8.0.0-preview.1.7762! p/1 Work that is important, and has been scheduled for release in this or an upcoming sprint platform/android 🤖 t/bug Something isn't working version/android-13
Milestone

Comments

@FatCodeMonkey
Copy link

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#
@UkeHa
Copy link

UkeHa commented Nov 11, 2022

@FatCodeMonkey does it work if you add android:requestLegacyExternalStorage="true" to your manifest?
<application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true" android:requestLegacyExternalStorage="true">>

@PureWeen PureWeen added this to the Backlog milestone Nov 11, 2022
@ghost
Copy link

ghost commented Nov 11, 2022

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

@PureWeen
Copy link
Member

@mattleibow @rachelkang

@Stedy59
Copy link

Stedy59 commented 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

@sidewinder94
Copy link

@Stedy59 Could you share your modifications while we wait for the MAUI team to fix this ? (right now as a workaround I fixed the target android sdk to 30 in the android manifest).

@YMichurin
Copy link

YMichurin commented Dec 1, 2022

I do not see how I can circumvent the issue either. Everyone around me has devices with the latest Android installed which I can't run my .net maui app on. The app can't work without media picker (MediaPicker control), but it seems to rely on WRITE_EXTERNAL_STORAGE only, which is not in the list of android permissions anymore. It does not care about new api 33 permissions like READ_MEDIA_IMAGES, it wants WRITE_EXTERNAL_STORAGE and does not run camera without it. Am I stuck till the issue is fixed in new ver of .net maui core, or there is some temp. workaround for that?

@sidewinder94
Copy link

sidewinder94 commented Dec 2, 2022

@YMichurin Unless you need what api 33 need, change the target SDK inside the android manifest to target api level 32. That did it for me

@YMichurin
Copy link

YMichurin commented Dec 2, 2022

hi @sidewinder94, if I do change the manifest to api 32 and let's say I do not use api 33 features, would my app work on a phone with the newest api 33 installed?

@Stedy59
Copy link

Stedy59 commented Dec 2, 2022

Here is a snippet that I use to open the device gallery and/or select a ringtone...

[assembly: UsesPermission(Name = "android.permission.READ_EXTERNAL_STORAGE", MaxSdkVersion = 32)]
[assembly: UsesPermission(Name = "android.permission.READ_MEDIA_AUDIO")]
[assembly: UsesPermission(Name = "android.permission.READ_MEDIA_IMAGES")]
[assembly: UsesPermission(Name = "android.permission.READ_MEDIA_VIDEO")]
namespace StedySoft.Shared {

	#region Class MediaServices
	public static partial class MediaServices {

		#region Declarations
		internal const int OPENGALLERY = 100;
		internal const int OPENRINGTONES = 101;
		#endregion

		#region Private Methods
		private static bool PlatformGetExternalStoragePermissions(string requestMessage, int permissionType = OPENGALLERY) {
			try {
				Permission status = Permission.Denied;
				if (Build.VERSION.SdkInt >= BuildVersionCodes.Tiramisu) {
					switch (permissionType) {
						case OPENGALLERY:
							status = ContextCompat.CheckSelfPermission(Application.Context, Manifest.Permission.ReadMediaImages);
							break;
						case OPENRINGTONES:
							status = ContextCompat.CheckSelfPermission(Application.Context, Manifest.Permission.ReadMediaAudio);
							break;
					}
				}
				else {
					status = ContextCompat.CheckSelfPermission(Application.Context, Manifest.Permission.ReadExternalStorage);
				}
				if (status != Permission.Granted) {
					if (Build.VERSION.SdkInt >= BuildVersionCodes.Tiramisu) {
						switch (permissionType) {
							case OPENGALLERY:
								if (ActivityCompat.ShouldShowRequestPermissionRationale(Platform.Activity, Manifest.Permission.ReadMediaImages)) { Toast.Show(requestMessage, ToastDuration.Long); }
								ActivityCompat.RequestPermissions(Platform.Activity, new[] { Manifest.Permission.ReadMediaImages }, 0);
								break;
							case OPENRINGTONES:
								if (ActivityCompat.ShouldShowRequestPermissionRationale(Platform.Activity, Manifest.Permission.ReadMediaAudio)) { Toast.Show(requestMessage, ToastDuration.Long); }
								ActivityCompat.RequestPermissions(Platform.Activity, new[] { Manifest.Permission.ReadMediaAudio }, 0);
								break;
						}
					}
					else {
						if (ActivityCompat.ShouldShowRequestPermissionRationale(Platform.Activity, Manifest.Permission.ReadExternalStorage)) { Toast.Show(requestMessage, ToastDuration.Long); }
						ActivityCompat.RequestPermissions(Platform.Activity, new[] { Manifest.Permission.ReadExternalStorage }, 0);
					}
					Stopwatch stopwatch = new();
					stopwatch.Start();
					do {
						Thread.Sleep(10);
						if (Build.VERSION.SdkInt >= BuildVersionCodes.Tiramisu) {
							switch (permissionType) {
								case OPENGALLERY:
									status = ContextCompat.CheckSelfPermission(Application.Context, Manifest.Permission.ReadMediaImages);
									break;
								case OPENRINGTONES:
									status = ContextCompat.CheckSelfPermission(Application.Context, Manifest.Permission.ReadMediaAudio);
									break;
							}
						}
						else {
							status = ContextCompat.CheckSelfPermission(Application.Context, Manifest.Permission.ReadExternalStorage);
						}
						if (stopwatch.ElapsedMilliseconds > 10000) {
							throw new Exception("Timed out waiting for permission.");
						}
					} while (status != Permission.Granted);
				}
				return true;
			}
			catch (Exception ex) {
				Logger.LogException("MediaServices", "PlatformGetExternalStoragePermissions", ex);
			}
			return false;
		}

@sidewinder94
Copy link

@YMichurin Yes, no issues there, since devices running higher versions know how to deal with older ones.

@espenrl
Copy link
Contributor

espenrl commented Dec 3, 2022

And here is the code

<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="32" />

@FM1973
Copy link

FM1973 commented Dec 13, 2022

Same here.
I had to set the targetSdkVersion to 32 to use Notifications.
A lot of people already user Android 13. It would be nice to have the new permissions implemented in Maui.

@HopInTheCloud
Copy link

I have the same issue. The question now is, how long will it take for them to release an update to fix this. Releasing updates seems to be taking a really long time.

@espenrl
Copy link
Contributor

espenrl commented Dec 17, 2022

I avoided this issue by using Xamarin.MediaGallery instead.

https://github.com/dimonovdd/Xamarin.MediaGallery

@symbiogenesis
Copy link
Contributor

I avoided this issue by using Xamarin.MediaGallery instead.

https://github.com/dimonovdd/Xamarin.MediaGallery

I tried this, and followed the readme file, with both the stable and preview release, but it just pops up a dialog saying "Can't connect to the camera" in the Android 13 Emulator with SDK level 33.

Are you on .NET6 like the sample? Is there some other trick to it?

@UkeHa
Copy link

UkeHa commented Jan 2, 2023

@symbiogenesis, again, if you don't need to target sdk33 just target 32 and it'll work just fine. Still a bug that needs to be fixed.

@symbiogenesis
Copy link
Contributor

symbiogenesis commented Jan 2, 2023

@symbiogenesis, again, if you don't need to target sdk33 just target 32 and it'll work just fine. Still a bug that needs to be fixed.

Thank you. I had tried this before and it didn't work for some reason, but I tried it now and it works. This is the best solution.

@davispalla
Copy link

I'm having the same problem. I'm following the colleague's last suggestion, that is, changing the destination to sdk 32.
Previously, I had used Xam.Media.Plugin, however, when I open the camera, vs closes and the app in debug mode also closes without throwing the error message.

@samhouts samhouts added the p/1 Work that is important, and has been scheduled for release in this or an upcoming sprint label Jan 5, 2023
@Ghostbird
Copy link
Contributor

Ghostbird commented Jan 19, 2023

@FatCodeMonkey does it work if you add android:requestLegacyExternalStorage="true" to your manifest? <application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true" android:requestLegacyExternalStorage="true">>

After you update your app to target Android 11, the system ignores the requestLegacyExternalStorage flag. [source]

So no, that's a completely different option that only worked before Android 11.

@Ghostbird
Copy link
Contributor

Ghostbird commented Jan 19, 2023

And here is the code

<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="32" />

How do you get that to work? If I do that I get:

warning XA4211: AndroidManifest.xml //uses-sdk/@android:targetSdkVersion '32' is less than $(TargetFrameworkVersion) ''. Using API-33 for ACW compilation. 

@espenrl The compilation still happens with API 33 and the MediaPicker.Capture methods won't work.

Because the warning mentions $(TargetFrameworkVersion), I tried adding a TargetFrameworkVersion option with value 32 to the build, but that didn't change a thing.

@YMichurin
Copy link

YMichurin commented Jan 19, 2023

And here is the code

<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="32" />

How do you get that to work? If I do that I get:

Double check that Targeting Android option is on in the project settings and it targets lower version. This is what I have in the project file and it works. I do not think you need anything else behind that to avoid the error

<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>

@Ghostbird
Copy link
Contributor

Ghostbird commented Jan 19, 2023

And here is the code

<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="32" />

How do you get that to work? If I do that I get:

Double check that Targeting Android option is on in the project settings and it targets lower version. This is what I have in the project file and it works. I do not think you need anything else behind that to avoid the error

<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>

Hmm… yes, that option is already in our csproj file, it's needed to build Android. This sets the minSdkVersion.

@symbiogenesis
Copy link
Contributor

I just ignored the XA4211 warning. It worked. I took photos successfully on Android 13, both with the real device and the emulator.

I think your PR is still very helpful, and I hope you continue to clean up that horrible code.

The iOS code is possibly even worse. The photos don't respect the device orientation, and it is using obsolete APIs with lots of TODOs and pragmas in the code.

@AHComp
Copy link

AHComp commented Mar 15, 2023 via email

@Ghostbird
Copy link
Contributor

No, this is a MAUI problem, not a .NET problem. We're waiting for the next .NET MAUI 7.0 service release.

@AHComp
Copy link

AHComp commented Mar 15, 2023

Ok and the date is ?

@Ghostbird
Copy link
Contributor

Ghostbird commented Mar 15, 2023 via email

@HurseyNZ
Copy link

@HurseyNZ I'm not familiar with the tooling you're using. I'm using plain dotnet to build. It may be that your IDE is preventing you from taking actions that are non-standard, even if completely valid. As @sidewinder94 says, you can change the setting in AndroidManifest.xml.

It's Visual Studio 2022 I'm using. Getting to the exact same point as @AHComp. Have tried many different versions of target SDK in the app manifest and project code, all result in Using API-33 for ACW Compliance

@Ghostbird
Copy link
Contributor

Ghostbird commented Mar 15, 2023 via email

@janseris
Copy link

janseris commented Mar 22, 2023

Hey does anybody try to publish a app downgraded to api 32 ? I got an error on try to publish !

image

Google Play has now policy that before August 31 2023, all new apps must target API 33.
That's ~3 months before .NET 8 will be released.
For this, releasing this in .NET 8 is late.
@samhouts I can see that you added label "fixed in .NET 7.0", that is good news. What service release will this be available in?


Quoted from mail from Google Play:

Starting August 31, 2023:

New apps and app updates must target API level 33 to be submitted to Google Play (Wear OS must target API 30). Existing apps must target API level 31 or above to remain discoverable by all users on Google Play. Apps that target API level 30 or below (target API level 29 or below for Wear OS), will only be discoverable on devices running Android OS same or lower than your apps’ target API level.
You will be able to request an extension to November 1, 2023 if you need more time to update your app. You'll be able to access your app's extension forms in Play Console later this year.

@AHComp
Copy link

AHComp commented Mar 22, 2023

@Redth How long it could take to add the service release for .Net 7 to visual studio ?

@Ghostbird
Copy link
Contributor

Ghostbird commented Mar 22, 2023 via email

@Ghostbird
Copy link
Contributor

Ghostbird commented Mar 22, 2023 via email

@janseris
Copy link

janseris commented Mar 22, 2023

This has nothing to do with Visual Studio. When .NET MAUI 7 service release is released, it should include the fix. You can install that update. It is possible that Visual Studio has a menu that performs the action for you, you can also use the .NET CLI. Or you could manually download the new version and replace the old version on your filesystem. My point is. Don't look for a solution in the wrong place. MAUI is its own thing.

On Wed, 22 Mar 2023, 14:35 AHComp, @.> wrote: @Redth https://github.com/Redth How long it could take to add the service release for .Net 7 to visual studio ? — Reply to this email directly, view it on GitHub <#11275 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAJFPZL5SS6JBGYU6GDC72DW5L5ZNANCNFSM6AAAAAAR5DB6KM . You are receiving this because you commented.Message ID: @.>

It has 100 % to do with Visual Studio because MAUI "workfload" is installed/updated when installing/updating Visual Studio.
It's been like that since at least 3/2022 - closely tied.

@Ghostbird
Copy link
Contributor

Ghostbird commented Mar 22, 2023 via email

@FM1973
Copy link

FM1973 commented Mar 22, 2023

@Ghostbird
How do you install the latest version of maui without a visual studio update?
As I´ve read, latest Visual Studio Versions contain a lot of bugs. But I´d like to have the lates maui release.

@Redth
Copy link
Member

Redth commented Mar 22, 2023

Looks like we backported the fix to net7.0 branches here: #12914

This will be available in the next .NET 7.0 servicing release of .NET MAUI (Service Release 4) which should be available within the next few weeks.

@Ghostbird
Copy link
Contributor

Ghostbird commented Mar 22, 2023 via email

@FM1973
Copy link

FM1973 commented Mar 22, 2023

@Ghostbird
So you say to install the latest .net core SDK (7.0.4) and then use dotnet workload update. Am I right?

@Ghostbird
Copy link
Contributor

Ghostbird commented Mar 22, 2023 via email

@guillaumedotnet
Copy link

Congratulations on the new release pack and thanks!

@ghost
Copy link

ghost commented Apr 11, 2023

Hello lovely human, thank you for your comment on this issue. Because this issue has been closed for a period of time, please strongly consider opening a new issue linking to this issue instead to ensure better visibility of your comment. Thank you!

@ghost
Copy link

ghost commented May 2, 2023

Hello lovely human, thank you for your comment on this issue. Because this issue has been closed for a period of time, please strongly consider opening a new issue linking to this issue instead to ensure better visibility of your comment. Thank you!

@Ghostbird
Copy link
Contributor

Ghostbird commented May 2, 2023

Anyone knows why this is still not working? Here's my dotnet SDK and MAUI versions:

image image

Your .NET SDK version is actually newer than mine (7.0.203), since you're running the preview. I think you're running a Visual Studio specific version of the dotnet workloads. I don't have experience with those.

You could try to install the maui workloads using the dotnet CLI.

In my case it lists this:

$ dotnet workload list
Installed Workload Id      Manifest Version      Installation Source
--------------------------------------------------------------------
maui-android               7.0.81/7.0.100        SDK 7.0.200

If dotnet is already in your PATH you can run. dotnet workload install maui-android. Replace maui-android with the appropriate other workloads to install those.

@Ghostbird
Copy link
Contributor

Ghostbird commented May 2, 2023

Yeah, our latest production release uses Android 13. I see that you're still on the .NET preview. Why are you trying this using a preview? I'd use the latest stable if I were you. If it works using the stable version, but not using the preview, please report a regression.

Did you follow the instructions higher up in this thread? If so, your Android manifest should contain these two lines (although your minSdkVersion may be different):

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

If you've tried all that and it still doesn't help, please post the actual error.

@zZHorizonZz
Copy link

Workaround

@Ghostbird
Copy link
Contributor

Ghostbird commented May 2, 2023

This issue is about android.permission.WRITE_EXTERNAL_STORAGE. As I think @zZHorizonZz implies, it seems your problem is with android.permissions.READ_EXTERNAL_STORAGE. In that case, this is not the right issue for you, but the workaround linked above may work.

@ghost ghost locked as resolved and limited conversation to collaborators Jun 1, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
fixed-in-7.0.81 Look for this fix in 7.0.81! fixed-in-7.0.100 fixed-in-7.0.101 fixed-in-8.0.0-preview.1.7762 Look for this fix in 8.0.0-preview.1.7762! p/1 Work that is important, and has been scheduled for release in this or an upcoming sprint platform/android 🤖 t/bug Something isn't working version/android-13
Projects
None yet