我正在try 让应用程序用户 Select 一个文件夹来保存从相机拍摄的照片.如果我需要使用与我正在使用的NuGet包或内置功能不同的NuGet包,我可以做到.我正在使用的是我发现的第一台有文件夹 Select 器的电脑,我可以开始工作了.
我已经阅读了几十篇文章、答案、问题、技术文档、演练、观看的视频等,试图访问以 Select 要保存的相机图像的文件夹.不幸的是,似乎什么都不起作用,因为我一直收到一个异常,说我没有"存储"权限,尽管我已经try 了几种方法来获得它们.我还申请了几乎所有与"存储"相关的权限,即使我不认为是真正的权限,但在我读到的一份文件中提到了它.
这可以在2台运行Android 9(API 28)和Android 12(API 31)的真实设备上运行,但不能在Android 13(API 33)设备上运行.我正在为FolderPicker使用最新的CommunityToolkit NuGet包.
查看专门针对该应用程序的权限,在"拒绝"部分中没有列出任何权限.
我知道这与我判断权限的定制方式无关,因为我使用它来请求蓝牙和other permissions.
接近底部的"FolderPickerResult"代码行返回异常.它不抛出它,而是将它返回给"Result"对象/变量.例外消息是"未授予存储权限".
这是返回的整个对象:
{
FolderPickerResult {
Folder = ,
Exception = Microsoft.Maui.ApplicationModel.PermissionException: Storage permission is not granted.at CommunityToolkit.Maui.Storage.FolderPickerImplementation.InternalPickAsync(String initialPath, CancellationToken cancellationToken)in / _ / src / CommunityToolkit.Maui.Core / Essentials / FolderPicker / FolderPickerImplementation.android.cs: line 18 at CommunityToolkit.Maui.Storage.FolderPickerImplementation.PickAsync(String initialPath, CancellationToken cancellationToken)in / _ / src / CommunityToolkit.Maui.Core / Essentials / FolderPicker / FolderPickerImplementation.shared.cs: line 11,
IsSuccessful = False
}
}
根据标题,我在毛伊岛的一个项目中使用C#.NET7.
我错过了什么/做错了什么?当我读到的每一本书都说它应该起作用的时候,为什么这个不起作用?
Here's my code, as minimal as possible:
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.XXX.XXX" android:versionCode="1">
<application android:allowBackup="true" android:icon="@mipmap/appicon" android:supportsRtl="true" android:label="XXX">
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"></meta-data>
</provider>
</application>
<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" />
<uses-permission android:name="android.permission.READ_STORAGE_PERMISSION" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_MEDIA" />
<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
<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" />
<queries>
<intent>
<action android:name="android.media.action.IMAGE_CAPTURE" />
</intent>
</queries>
</manifest>
GalleryPermissions.cs
using static Microsoft.Maui.ApplicationModel.Permissions;
namespace Namespace;
internal class GalleryPermissions : BasePlatformPermission
{
#if ANDROID
public override (string androidPermission, bool isRuntime)[] RequiredPermissions =>
new List<(string permission, bool isRuntime)>
{
("android.permission.WRITE_EXTERNAL_STORAGE", true),
("android.permission.READ_EXTERNAL_STORAGE", true),
("android.permission.MANAGE_EXTERNAL_STORAGE", true),
("android.permission.MANAGE_MEDIA", true),
("android.permission.READ_MEDIA_IMAGES", true),
("android.permission.READ_MEDIA_AUDIO", true),
("android.permission.READ_MEDIA_VIDEO", true),
("android.permission.READ_STORAGE_PERMISSION", true),
("android.permission.MEDIA_CONTENT_CONTROL", true)
}.ToArray();
#endif
}
MainPage.xaml.cs
using CommunityToolkit.Maui.Storage;
protected override async void OnAppearing()
{
base.OnAppearing();
PermissionStatus storageWriteStatus = await CheckPermission<Permissions.StorageWrite>(); // always "denied"
PermissionStatus storageReadStatus = await CheckPermission<Permissions.StorageRead>(); // always "denied"
PermissionStatus galleryStatus = await CheckPermission<GalleryPermissions>(); // always "denied"
...
}
private static async Task<PermissionStatus> CheckPermission<TPermission>() where TPermission : Permissions.BasePermission, new()
{
PermissionStatus status = await Permissions.CheckStatusAsync<TPermission>();
if (status != PermissionStatus.Granted)
{
status = await Permissions.RequestAsync<TPermission>();
}
return status;
}
private async void SelectButton_Clicked(object sender, EventArgs e)
{
CancellationTokenSource source = new();
// SaveLocation.Text is originally string.Empty, but even if I put in a breakpoint and set
// it to the same "/storage/emulated/0/DCIM/Camera" that I get returned on other devices,
// I still get an Exception and result.IsSuccessful is `false`
FolderPickerResult result = await FolderPicker.PickAsync(SaveLocation.Text, source.Token);
//FolderPickerResult result = await FolderPicker.Default.PickAsync(SaveLocation.Text, source.Token); // This is the same as the line above
if (result.IsSuccessful)
{
SaveLocation.Text = result.Folder.Path;
}
else
{
// On API 33, this always prints "Storage Permission is not granted.", except when
// I try to remove permissions I've read aren't needed for API 33.
await Toast.Make($"{result.Exception.Message}").Show(source.Token);
Error.Text = result.Exception.Message;
}
}
以下是我用来调试我的应用程序并运行Android 13(API 33)的真正Android设备的屏幕截图,它恰好是三星Galaxy A03s Tracfone.我已经包含了该应用程序的权限页面.