检查和请求毛伊岛权限(包括蓝牙)的简单方法?

com*_*guy 3 c# permissions maui

我正在寻找一种简单的方法来查询和请求 .Net Maui 中的多个权限。我还需要请求蓝牙权限,但据我所知,毛伊岛没有内置的蓝牙权限。我在 2022 年最后一次听到的消息是,毛伊岛路线图中没有蓝牙,我觉得这是相当短视的。

我读了很多文章、问答、文档、观看了视频,并做了很多其他研究来解决这个问题。

到目前为止,我可以检查并请求个人权限,但我正在寻找比重复更干燥的东西:

PermissionStatus status = await Permissions.CheckStatusAsync<Permissions.XXX>();

if (status != PermissionStatus.Granted){
    status = await Permissions.RequestAsync<Permissions.XXX>();
}
Run Code Online (Sandbox Code Playgroud)

对于每一个许可。我需要多个权限,因此我的检查很快就会失控。

顺便说一句,根据 Google Play 的要求,我的目标是 Android 13.0。

我知道这要求很高,但我迷失在所有建议中,其中许多建议不起作用,所以帮助解决所有这些问题就太好了!

com*_*guy 8

我使用了许多不同的来源来将其组合在一起,但这些是最有用的。

可用的 Maui 权限:https://learn.microsoft.com/en-us/dotnet/maui/platform-integration/appmodel/permissions
主线程权限:/sf/answers/5290219931/
蓝牙和自定义权限:https://www.youtube.com/watch?
v=9GljgwfpiiE 位置服务检查:/sf/answers/4841110221/

为了使这更容易理解,我将把所有代码留到最后。

另外,我的项目面向 .Net 7.0、Android 13.0 (API 33)、iOS 11.0 和 Windows 10.0.19041.0 当前的 Google Play 要求。我还没有检查这是否适用于 iOS 或 Windows,但这至少让你/我在运行这些其他操作系统方面迈出了几步。更改 JIT 编译器的目标操作系统时,VS 2022 不会引发任何错误,因此它应该可以工作。如果没有,那么与 1-5 年前的建议或专为 Android 编写的 Java 建议相比,需要做的调整应该更少。

第一的

您需要设置 Manifest 和 .plist 文件以获得满足您需求的正确权限。我不打算在这里详细介绍这一点,因为它在我上面链接的第一个参考文献中已经很好地介绍了。

第二

我建议将权限检查代码放入辅助方法中。由于这将是一个async方法,因此您需要从“OnAppearing”方法中调用它,您必须重写该方法并 make async

我让我的辅助方法返回 a bool,这样我就可以检查是否所有权限都被接受,因为我的应用程序需要我请求的所有权限。没有他们,它根本就不会做任何事。为了轻松检查权限是否被授予/限制,我为此添加了另一种方法,因为我要检查太多权限。

第三

您可以将个体CheckStatusAsync和移至RequestAsync通用方法并简单地调用它以帮助防止重复。

第四

由于您/我需要蓝牙访问,因此您必须编写自定义权限检查器,但仅适用于 Android,不适用于 iOS 或 Windows。这并不难,但是没有太多资源可以向您展示如何操作,而且也不容易找到。

第五

显然,如果手机上的定位服务未启用,则这些对于蓝牙权限都无关紧要。如果您的应用程序可以扫描蓝牙设备,但没有找到任何设备,则很有可能手机的定位服务未启用。我必须添加一个 Toast,以便在扫描返回零结果时让用户知道这是必要的。

或者您可以使用操作系统特定的方法直接检查位置服务状态。

代码

MainPage.xaml.cs:

using CommunityToolkit.Maui.Alerts; // For the Toast

#if ANDROID
using Android.Content;
using Android.Locations;
#elif IOS || MACCATALYST
using CoreLocation;
#elif WINDOWS
using Windows.Devices.Geolocation;
#endif

    protected override async void OnAppearing()  
    {  
        base.OnAppearing();  

        if (!await CheckPermissions())
        {
            await Toast.Make("Not all permissions were accepted. Application will close.").Show();
            Application.Current.Quit();
        }
    } 

    private async Task<bool> CheckPermissions()
    {
        PermissionStatus bluetoothStatus = await CheckBluetoothPermissions();
        PermissionStatus cameraStatus = await CheckPermissions<Permissions.Camera>();
        PermissionStatus mediaStatus = await CheckPermissions<Permissions.Media>();
        PermissionStatus storageWriteStatus = await CheckPermissions<Permissions.StorageWrite>();
        //PermissionStatus photosStatus = await CheckPermissions<Permissions.Photos>();
        ...

        bool locationServices = IsLocationServiceEnabled();

        return IsGranted(cameraStatus) && IsGranted(mediaStatus) && IsGranted(storageWriteStatus) && IsGranted(bluetoothStatus);
    }

    private async Task<PermissionStatus> CheckBluetoothPermissions()
    {
        PermissionStatus bluetoothStatus = PermissionStatus.Granted;

        if (DeviceInfo.Platform == DevicePlatform.Android)
        {
            if (DeviceInfo.Version.Major >= 12)
            {
                bluetoothStatus = await CheckPermissions<BluetoothPermissions>();
            }
            else
            {
                bluetoothStatus = await CheckPermissions<Permissions.LocationWhenInUse>();
            }
        }

        return bluetoothStatus;
    }

    private async Task<PermissionStatus> CheckPermissions<TPermission>() where TPermission : Permissions.BasePermission, new()
    {
        PermissionStatus status = await Permissions.CheckStatusAsync<TPermission>();

        if (status != PermissionStatus.Granted){
            status = await Permissions.RequestAsync<TPermission>();
        }

        return status;
    }

    private static bool IsGranted(PermissionStatus status)
    {
        return status == PermissionStatus.Granted || status == PermissionStatus.Limited;
    }

#if ANDROID
    private bool IsLocationServiceEnabled()
    {
        LocationManager locationManager = (LocationManager)Android.App.Application.Context.GetSystemService(Context.LocationService);
        return locationManager.IsProviderEnabled(LocationManager.GpsProvider);
    }
#elif IOS || MACCATALYST
    public bool IsLocationServiceEnabled()
    {
        return CLLocationManager.Status == CLAuthorizationStatus.Denied;
    }
#elif WINDOWS
    private bool IsLocationServiceEnabled()
    {
        Geolocator locationservice = new Geolocator();
        return locationservice.LocationStatus == PositionStatus.Disabled;
    }
#endif
Run Code Online (Sandbox Code Playgroud)

在您的项目中创建一个名为“BluetoothPermissions.cs”的新文件:

using static Microsoft.Maui.ApplicationModel.Permissions;

namespace YourNamespace;

internal class BluetoothPermissions : BasePlatformPermission
{
#if ANDROID
    public override (string androidPermission, bool isRuntime)[] RequiredPermissions =>
        new List<(string permission, bool isRuntime)>
        {
            ("android.permission.BLUETOOTH", true),
            ("android.permission.BLUETOOTH_ADMIN", true),
            ("android.permission.BLUETOOTH_SCAN", true),
            ("android.permission.BLUETOOTH_CONNECT", true),
            ("android.permission.ACCESS_COARSE_LOCATION", true),
            ("android.permission.ACCESS_FINE_LOCATION", true)
        }.ToArray();
  // This list includes Bluetooth LE permissions.
  //  You will need to include these permissions in your Android Manifest, too.
#endif
}
Run Code Online (Sandbox Code Playgroud)

注意:当我继续开发此应用程序时,我正在寻找无需所有权限即可使用功能的方法,例如蓝牙。当我使这些功能能够打开和关闭时,我发现我越来越有可能必须在“主页”以外的设置页面上检查这些权限。我可能最终会将大多数(如果不是全部)这些权限转换为它自己的类,这样我就可以从我将打开和关闭功能的各个位置访问它。如果我这样做,我将保留这个答案,并做出一个新答案(如果它与这个答案有显着不同)。

  • 出色的!您可以检查[接受您自己的答案](https://stackoverflow.blog/2009/01/06/accept-your-own-answers/?_ga=2.79938071.1265980644.1684110527-530046372.1660608907),因为这对面临同样问题的其他人有帮助。 (2认同)