Closed Jon2G closed 1 year ago
@microsoft-github-policy-service agree
please merge
Please merge this PR, our customers already complain a lot
Any news on this? Our app is useless in Android 13 because of this bug. Please merge and publish as soon as possible.
@simader @daflotsch you can easily implement this yourself by extending the current permissions as described in our documentation: https://learn.microsoft.com/xamarin/essentials/permissions?tabs=android#extending-permissions
As mentioned in this PR also about permissions, Xamarin.Essentials is in maintanance only and we're not looking to add new functionality unless we absolutely have to. New development will happen in .NET MAUI.
@jfversluis
I was under the impression that when you guys said that Xamarin would support up to android 13 (even under maintenance), this kind of issue would still be addressed. But thank you for clarifying it.
I just have to deal with permission issues in a 5 years old Xamarin app. Also facing pressure for release as it has to support a new product.
To my knowledge, Xamarin EOL date is currently May 1, 2024. Therefore, I do not understand statements like "Xamarin.Essentials is in maintanance only and we're not looking to add new functionality unless we absolutely have to.". This is not acceptable. We need running Xamarin products until this date. And if Android or iOS are making changes that break general usability, this is a "have to". I wonder if others see it the same way...
@Kukulkano
/agree
While they don't move, this is what you can do to make it work.
add permissions to manifest
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
Extend BasePlatformPermission
public class ReadImagesVideoPermission : Xamarin.Essentials.Permissions.BasePlatformPermission, IReadImagesVideoPermission
{
public override (string androidPermission, bool isRuntime)[] RequiredPermissions => new List<(string androidPermission, bool isRuntime)> {
("android.permission.READ_MEDIA_IMAGES", true),
("android.permission.READ_MEDIA_VIDEO", true)
}.ToArray();
}
In my case, i had to trick xam essentials in thinking the old permissions (ex: read_external_storage) were granted in android 13.
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
if (Xamarin.Essentials.DeviceInfo.Version.Major >= 13
&& (permissions.Where(p => p.Equals("android.permission.WRITE_EXTERNAL_STORAGE")).Any()
|| permissions.Where(p => p.Equals("android.permission.READ_EXTERNAL_STORAGE")).Any()))
{
var wIdx = Array.IndexOf(permissions, "android.permission.WRITE_EXTERNAL_STORAGE");
var rIdx = Array.IndexOf(permissions, "android.permission.READ_EXTERNAL_STORAGE");
if (wIdx != -1 && wIdx < permissions.Length) grantResults[wIdx] = Permission.Granted;
if (rIdx != -1 && rIdx < permissions.Length) grantResults[rIdx] = Permission.Granted;
}
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
Call the dependency service
if (DeviceInfo.Platform.Equals(DevicePlatform.Android) && DeviceInfo.Version.Major >= 13)
{
var readImagesVideoPermission = DependencyService.Get<IReadImagesVideoPermission>();
var permission = await readImagesVideoPermission.CheckStatusAsync();
if (permission != PermissionStatus.Granted)
{
// Prompt the user with additional information as to why the permission is needed
if (rationale != null) await rationale();
permission = await readImagesVideoPermission.RequestAsync();
}
return permission;
}
Hi @WanftMoon really thank you for your solution. In my case, i only had to do step 3 of your suggestion in order to ge tthis to work.
I changed the OnRequestPermissionResult, and added the lines you suggested, and also updated my manifest - and it works. I did not have to implement a Interface (i think this is because my manifest already included the new permissions.
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
if (Xamarin.Essentials.DeviceInfo.Version.Major >= 13 && (permissions.Where(p => p.Equals("android.permission.WRITE_EXTERNAL_STORAGE")).Any() || permissions.Where(p => p.Equals("android.permission.READ_EXTERNAL_STORAGE")).Any()))
{
var wIdx = Array.IndexOf(permissions, "android.permission.WRITE_EXTERNAL_STORAGE");
var rIdx = Array.IndexOf(permissions, "android.permission.READ_EXTERNAL_STORAGE");
if (wIdx != -1 && wIdx < permissions.Length) grantResults[wIdx] = Permission.Granted;
if (rIdx != -1 && rIdx < permissions.Length) grantResults[rIdx] = Permission.Granted;
}
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
Manifest
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!--<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />-->
<uses-feature android:name="android.hardware.location" android:required="false" />
<uses-feature android:name="android.hardware.location.gps" android:required="false" />
<uses-feature android:name="android.hardware.location.network" android:required="false" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
@Kukulkano
/agree
While they don't move, this is what you can do to make it work.
- add permissions to manifest
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
- Extend BasePlatformPermission
public class ReadImagesVideoPermission : Xamarin.Essentials.Permissions.BasePlatformPermission, IReadImagesVideoPermission { public override (string androidPermission, bool isRuntime)[] RequiredPermissions => new List<(string androidPermission, bool isRuntime)> { ("android.permission.READ_MEDIA_IMAGES", true), ("android.permission.READ_MEDIA_VIDEO", true) }.ToArray(); }
In my case, i had to trick xam essentials in thinking the old permissions (ex: read_external_storage) were granted in android 13. ` public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults) { if (Xamarin.Essentials.DeviceInfo.Version.Major >= 13 && (permissions.Where(p => p.Equals("android.permission.WRITE_EXTERNAL_STORAGE")).Any() || permissions.Where(p => p.Equals("android.permission.READ_EXTERNAL_STORAGE")).Any())) { var wIdx = Array.IndexOf(permissions, "android.permission.WRITE_EXTERNAL_STORAGE"); var rIdx = Array.IndexOf(permissions, "android.permission.READ_EXTERNAL_STORAGE");
if (wIdx != -1 && wIdx < permissions.Length) grantResults[wIdx] = Permission.Granted; if (rIdx != -1 && rIdx < permissions.Length) grantResults[rIdx] = Permission.Granted; } Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults); base.OnRequestPermissionsResult(requestCode, permissions, grantResults); }`
Call the dependency service ` if (DeviceInfo.Platform.Equals(DevicePlatform.Android) && DeviceInfo.Version.Major >= 13) { var readImagesVideoPermission = DependencyService.Get();
var permission = await readImagesVideoPermission.CheckStatusAsync(); if (permission != PermissionStatus.Granted) { // Prompt the user with additional information as to why the permission is needed if (rationale != null) await rationale(); permission = await readImagesVideoPermission.RequestAsync(); } return permission; }`
Will this still work with a min SDK of <33 specified? Or do both min and target SDK have to be 33? And so should the READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE entries in the manifest just stay as there are or be removed? Our min SDK is version 27 and so I'm wondering if we need to require users to go to 33...
Will this still work with a min SDK of <33 specified? Or do both min and target SDK have to be 33? And so should the READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE entries in the manifest just stay as there are or be removed?
Yeah, it will. My mininum is 26 right now and target is 33. And you need those permissions to devices below 33.
Will this still work with a min SDK of <33 specified? Or do both min and target SDK have to be 33? And so should the READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE entries in the manifest just stay as there are or be removed?
Yeah, it will. My mininum is 26 right now and target is 33.
So your manifest simply has all these entries (without specifying "minSdkVersion" and "maxSdkVersion" attributes)?
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
<uses-permission android:name="android.permission.CAMERA" />
So your manifest simply has all these entries (without specifying "minSdkVersion" and "maxSdkVersion" attributes)?
yup
<uses-sdk android:minSdkVersion="26" android:targetSdkVersion="33" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
So your manifest simply has all these entries (without specifying "minSdkVersion" and "maxSdkVersion" attributes)?
yup
<uses-sdk android:minSdkVersion="26" android:targetSdkVersion="33" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
You are the man! Thanks.
Adds Granular media permissions for Android 13+ https://developer.android.com/about/versions/13/behavior-changes-13#granular-media-permissions
Description of Change
Adds Granular media permissions for Android 13+ Starting from Android 13 you can no longer request STORAGE_READ, and STORAGE_WRITE permissions. Instead, you have to ask for granular permissions: READ_MEDIA_IMAGES READ_MEDIA_VIDEO READ_MEDIA_AUDIO
Bugs Fixed
Provide links to issues here. Ensure that a GitHub issue was created for your feature or bug fix before sending PR.
https://github.com/xamarin/Essentials/issues/2037 https://github.com/xamarin/Essentials/issues/2041
API Changes
None
Behavioral Changes
None
PR Checklist
main
at time of PR