Android 13:Xamarin.Forms 不授予访问库图像的权限

Android 13: Xamarin.Forms doesn't give permissions to access gallery images

提问人:Marcel Delhaye 提问时间:11/10/2023 最后编辑:Marcel Delhaye 更新时间:11/17/2023 访问量:86

问:

自 Android 13 以来,我的 Xamarin.Forms 应用不再具有访问库中图像所需的权限。我知道 Google 已经更改了访问条件,我们需要用细粒度媒体权限替换READ_EXTERNAL_STORAGE:READ_MEDIA_IMAGES、READ_MEDIA_VIDEO和READ_MEDIA_AUDIO。 我已经应用了所有这些更改,但对图像的访问仍然被拒绝(我没有来自系统的权限请求)。更糟糕的是,当我自己手动分配权限时,它也不起作用。最后,Xamarin.Essentials 组件(我使用的是 1.8.0 版)似乎没有考虑 Android 13 施加的更改。有更新计划吗?有没有办法解决这个问题? 这是我的AndroidManifest.xml文件:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.ApriSoft.memocourses" android:installLocation="auto" android:versionName="5.0.3" android:versionCode="503">
<uses-sdk android:minSdkVersion="20" android:targetSdkVersion="33" />
<application android:label="MemoCourses.Android">
    <activity android:name="microsoft.identity.client.BrowserTabActivity" android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data android:scheme="msauth" android:host="com.ApriSoft.memocourses" />
        </intent-filter>
    </activity>
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />

和 MainActivity.cs 文件:

using System;
using Xamarin.Forms.Platform.Android;
using Xamarin.Forms;
using static MemoCourses.Droid.MainActivity;
using Android.Content;
using Microsoft.Identity.Client;
using Xamarin.Essentials;
using MemoCourses.Models;
using System.Collections.ObjectModel;
using Android.Text.Method;
using Android.Text;
using Plugin.CurrentActivity;

[assembly: ExportRenderer(typeof(Entry), typeof(MyEntryRenderer))]
[assembly: UsesPermission(Android.Manifest.Permission.Camera)]
[assembly: UsesPermission(Android.Manifest.Permission.ReadMediaImages)]/* CSS Document*/

namespace MemoCourses.Droid
{
    [Activity(Label = "MemoCourses", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation, ScreenOrientation = ScreenOrientation.Portrait)]
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
    {
        protected override void OnCreate(Bundle savedInstanceState)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;
            base.OnCreate(savedInstanceState);
            Rg.Plugins.Popup.Popup.Init(this);

            Xamarin.Essentials.Platform.Init(this, savedInstanceState);
            global::Xamarin.Forms.Forms.Init(this, savedInstanceState);

            LoadApplication(new App());
            App.AuthUIParent = this;
            Window.SetStatusBarColor(Android.Graphics.Color.Argb(255, 47, 56, 40));
            ButtonCircleRenderer.Init();
        }

        public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
        {
            Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
            base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
       global::ZXing.Net.Mobile.Android.PermissionsHandler.OnRequestPermissionsResult(requestCode, permissions, grantResults);
        }

        protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
        {
            base.OnActivityResult(requestCode, resultCode, data);
        
AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(requestCode, resultCode, data);
        }

        public override void OnBackPressed()
        {
            Rg.Plugins.Popup.Popup.SendBackPressed(base.OnBackPressed);
        }
    }
}

这是我用来选择图像的代码:

try
{
    FileData fileData = await CrossFilePicker.Current.PickFile();
    //
    var filepath = fileData.FilePath;
    //
    if (fileData == null)
        return; // user canceled file picking
    
    newimageByte = fileData.DataArray;
    resizedImageByte = await ImageResizer.ResizeImage(newimageByte, 200, 200);

    if (resizedImageByte != null)
    {
        var stream1 = new MemoryStream(resizedImageByte);
        ImageArticle.Source = ImageSource.FromStream(() => stream1);
    }
}
catch (Exception ex)
{
    
    imageGallery = false;
    imageChanged = false;
}

非常感谢你对我的帮助,我已经找了好几天了,找不到解决方案。我的应用的所有用户(其手机已更新到 Android 13)都无法再从图库中选择图像。

Android Xamarin.Forms 权限

评论

0赞 blackapps 11/10/2023
app no longer has the required permissions to access the images in the gallery.不知道你认为什么 “画廊”在Android设备上。但是使用普通的 Android 图像或文件选择器,永远不需要任何权限即可这样做。也不用于访问使用获得的 uri 的文件。
0赞 blackapps 11/10/2023
can no longer upload an image上传?这是第三步。首先是采摘和打开。
0赞 Marcel Delhaye 11/11/2023
@blackapps我认为您不太了解 Xamarin.forms 甚至 Andoid,因为“图库”一词是所有 Android 手机上正式使用的术语,用于指定存储所有图像的位置。而且我不是唯一一个提出这个问题的人......
0赞 blackapps 11/11/2023
Android 设备上的图像可以存储在任何地方。并且可以有一个名为 Gallery 的应用程序。并且没有存储所有图像的位置,也没有图库。无论如何,不需要任何权限。你没有对此做出反应。虽然这是你的问题。
0赞 Marcel Delhaye 11/12/2023
我可能表达错了,但请查看此链接(github.com/xamarin/Essentials/issues/2041)

答:

0赞 Guangyu Bai - MSFT 11/13/2023 #1

我在我这边测试了该方法,效果很好。您可以使用以下代码在 Android 13 上上传图片。请把代码放在班级里。MainActivity

   public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] 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;
                }
    
                Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
                PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
            }

我制作了一个演示,你可以尝试使用它通过 Xamarin.Essentials: Media Picker 从照片中获取图像。

下面是 Mainpage.xaml 中的代码。

 <Image x:Name="FotoProduto"></Image>
 <Button x:Name="button" Text="button" Clicked="button_Clicked"></Button>

Mainpage.xaml.cs 中的代码。

private async void button_Clicked(object sender, EventArgs e)
        {
            var result = await MediaPicker.PickPhotoAsync(new MediaPickerOptions
            {
                Title = "Choise the product photo"
            });

            var stream = await result.OpenReadAsync();

            FotoProduto.Source = ImageSource.FromStream(() => stream);


        }

Mainpage.xaml.cs 中的更新方法

不要使用流方式。

  var result = await MediaPicker.PickPhotoAsync(new MediaPickerOptions
            {
                Title = "Choise the product photo"
            });
            var newFile = Path.Combine(FileSystem.CacheDirectory, result.FileName);

            FotoProduto.Source = newFile;

评论

0赞 Marcel Delhaye 11/14/2023
感谢您的回答,但不幸的是,我将您给我的代码添加到了 MainActivity.cs 文件中,但它不起作用。我在问题中添加了用于选择图像的代码部分。这是拒绝访问的地方。也许是 CrossFilePicker 命令导致了问题?
0赞 Guangyu Bai - MSFT 11/15/2023
CrossFilePicker不再受支持。可以使用 Xamarin.Essentials: Media Picker 选取照片或库中的图像。
0赞 Guangyu Bai - MSFT 11/15/2023
我编辑了我的答案以提供代码,您可以使用它来获取照片。
0赞 Marcel Delhaye 11/16/2023
再次感谢,但现在我有另一个问题:在这行代码上,流是正确的(CanRead = true CanWrite = false Length = 2237991),但下一行给了我错误。还有.为什么?谢谢你的帮助。var stream = await result.OpenReadAsync();Length = System.ObjectDisposedException: Cannot access a disposed objectObject name: 'Stream has been closed'. System.ArgumentNullException: 'Buffer cannot be null. Parameter name: buffer'
0赞 Guangyu Bai - MSFT 11/17/2023
您可以使用这些代码,而不是使用流。var result = await MediaPicker.PickPhotoAsync(new MediaPickerOptions { Title = "Choise the product photo" }); var newFile = Path.Combine(FileSystem.CacheDirectory, result.FileName); FotoProduto.Source = newFile;