我试图让应用程序用户选择一个文件夹来保存从相机拍摄的照片。如果我需要使用与我正在使用的不同的 NuGet 包或内置功能,我可以这样做。我使用的是我发现的第一个有文件夹选择器并且我可以开始工作的。
我阅读了数十篇文章、答案、问题、技术文档、演练、观看视频等,尝试访问并选择要保存相机图像的文件夹。不幸的是,似乎没有任何效果,因为我不断收到异常,说我没有“存储”权限,尽管我已经尝试了多种方法来获取它们。我还请求几乎所有与“存储”相关的权限,甚至是我认为不是真正权限的权限,但在我读过的其中一份文档中引用了它。
这适用于运行 Android 9 (API 28) 和 Android 12 (API 31) 的 2 台真实设备,但不适用于 Android 13 (API 33) 设备。我正在为FolderPicker使用最新的CommunityToolkit NuGet 包。
查看专门针对该应用程序的权限,“拒绝”部分中没有列出任何权限。
我知道这与我检查权限的自定义方式无关,因为我使用它来请求蓝牙和其他权限。
靠近底部的“FolderPickerResult”代码行返回异常。它不会抛出它,而是将其返回到“结果”对象/变量。异常消息是“未授予存储权限”。
这是返回的整个对象:
{
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
}
}
Run Code Online (Sandbox Code Playgroud)
根据标题,我在毛伊岛项目中使用 C# .Net 7。
所以,我的问题是:我错过了什么/做错了什么?当我读到的所有内容都说它应该起作用时,为什么这不起作用?
这是我的代码,尽可能少:
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>
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)
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;
}
}
Run Code Online (Sandbox Code Playgroud)
以下是我用来调试应用程序并运行 Android 13 (API 33) 的真实 Android 设备的屏幕截图,该设备恰好是三星 Galaxy A03s Tracfone。我已经包含了该应用程序的权限页面。
当我尝试将我的应用程序发布到 Google Play 商店时,我最初被拒绝,因为我试图使用该MANAGE_EXTERNAL_STORAGE权限。我删除了它,我的应用程序被允许发布。几周后,该应用程序被从商店中删除,因为它不符合 API 33 要求,尽管它是在早期 API 要求的截止日期之前发布的。我更新了 API 级别并在 API 33 设备上重新测试了文件夹选择器,没有任何问题。
这让我认为权限MANAGE_EXTERNAL_STORAGE和 API 33 的某种组合干扰了文件夹选择器功能。我不知道它是什么,但这是我改变的唯一两件事(技术上是一件事),现在它按预期工作。
这是 CommunityToolkit.Maui 包的问题。根据github上的资源代码var status = await Permissions.RequestAsync<Permissions.StorageRead>().WaitAsync(cancellationToken).ConfigureAwait(false);,如果的值为PermissionStatus.Denied,则会抛出此异常错误。
对于目标android 13,<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />已删除,因此有关权限请求的对话框永远不会出现在android 13或更高版本上。的值Permissions.RequestAsync<Permissions.StorageRead>将永远是PermissionStatus.Denied。
因此,您可以将应用程序的目标 Android 版本更改为 Android 12,以使READ_EXTERNAL_STORAGE权限请求警报仍然出现在 Android 13 或更高版本的设备上。在AndroidManifest.xml中添加以下代码:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="31" />
Run Code Online (Sandbox Code Playgroud)
您还可以在 github 上发布 CommunityToolkit.Maui 包的新问题。
| 归档时间: |
|
| 查看次数: |
2860 次 |
| 最近记录: |