Permissões

Procurar amostra. Procurar no exemplo

Este artigo descreve como você pode usar a classe Permissions da interface do usuário do aplicativo .NET multiplataforma (.NET MAUI). Essa classe permite que você verifique e solicite permissões em tempo de execução. O tipo Permissions está disponível no namespace Microsoft.Maui.ApplicationModel.

Permissões disponíveis

O .NET MAUI tenta abstrair o máximo de permissões possível. No entanto, cada sistema operacional tem um conjunto diferente de permissões. Embora a API permita o acesso a uma permissão comum, pode haver diferenças entre os sistemas operacionais relacionados a essa permissão. A tabela a seguir descreve as permissões disponíveis:

A tabela a seguir usa ✔️ para indicar que a permissão tem suporte e ❌ para indicar que a permissão não tem suporte ou não é necessária:

Permissão Android iOS Windows tvOS
Bateria ✔️
Bluetooth ✔️
CalendarRead ✔️ ✔️
CalendarWrite ✔️ ✔️
Câmera ✔️ ✔️
ContactsRead ✔️ ✔️
ContactsWrite ✔️ ✔️
Lanterna ✔️
LocationWhenInUse ✔️ ✔️ ✔️
LocationAlways ✔️ ✔️
Media ✔️
Microfone ✔️ ✔️
NearbyWifiDevices ✔️
NetworkState ✔️
Telefone ✔️ ✔️
Photos ✔️ ✔️
PhotosAddOnly ✔️ ✔️
Notificações Post ✔️
Lembretes ✔️
Sensores ✔️ ✔️
Sms ✔️ ✔️
Fala ✔️ ✔️
StorageRead ✔️
StorageWrite ✔️
Vibrar ✔️

Se uma permissão estiver marcada como ❌, ela sempre retornará Granted quando marcada ou solicitada.

Verificar permissões

Para verificar o status atual de uma permissão, use o método Permissions.CheckStatusAsync com a permissão específica para obter o status. O exemplo a seguir verifica o status da permissão LocationWhenInUse:

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

Um PermissionException será gerado se a permissão necessária não for declarada.

É melhor verificar o status da permissão antes de solicitá-la. Cada sistema operacional retornará um estado padrão diferente, se o usuário nunca tiver sido solicitado. O iOS retorna Unknown, enquanto outros retornam Denied. Se o status for Granted, não será necessário fazer outras chamadas. No iOS, se o status for Denied, você deverá solicitar que o usuário altere a permissão nas configurações. No Android, você pode chamar ShouldShowRationale para detectar se o usuário já negou a permissão no passado.

Status da permissão

Ao usar CheckStatusAsync ou RequestAsync, um PermissionStatus é retornado que pode ser usado para determinar as próximas etapas:

  • Unknown
    A permissão está em um estado desconhecido ou, no iOS, o usuário nunca foi solicitado.

  • Denied
    O usuário negou a solicitação de permissão.

  • Disabled
    O recurso está desabilitado no dispositivo.

  • Granted
    O usuário concedeu permissão ou ela é concedida automaticamente.

  • Restricted
    Em um estado restrito.

  • Limited
    Em um estado limitado. Somente o iOS retorna esse status.

Solicitar permissões

Para solicitar uma permissão dos usuários, use o método RequestAsync com a permissão específica. Se o usuário concedeu permissão anteriormente e não a revogou, esse método retornará Granted sem mostrar uma caixa de diálogo para o usuário. As permissões não devem ser solicitadas da sua classe MauiProgram ou App e só devem ser solicitadas quando a primeira página do aplicativo for exibida.

O exemplo a seguir solicita a permissão LocationWhenInUse:

PermissionStatus status = await Permissions.RequestAsync<Permissions.LocationWhenInUse>();

Um PermissionException será gerado se a permissão necessária não for declarada.

Importante

Em algumas plataformas, uma solicitação de permissão só pode ser ativada uma única vez. Outras solicitações devem ser tratadas pelo desenvolvedor para verificar se uma permissão está no estado Denied e, em seguida, pedir ao usuário para ativá-la manualmente.

Explicar por que a permissão é necessária

É uma prática recomendada explicar ao usuário por que seu aplicativo precisa de uma permissão específica. No iOS, você deve especificar uma cadeia de caracteres que será exibida ao usuário. O Android não tem essa capacidade e também define o status de permissão como Disabled por padrão. Isso limita a capacidade de saber se o usuário negou a permissão ou se é a primeira vez que a permissão está sendo solicitada. O método ShouldShowRationale pode ser usado para determinar se uma interface do usuário informativa deve ser exibida. Se o método retornar true, isso ocorre porque o usuário negou ou desabilitou a permissão no passado. Outras plataformas sempre retornam false ao chamar esse método.

Exemplo

O código a seguir apresenta o padrão de uso geral para determinar se uma permissão foi concedida e, em seguida, solicitá-la caso não tenha sido.

public async Task<PermissionStatus> CheckAndRequestLocationPermission()
{
    PermissionStatus status = await Permissions.CheckStatusAsync<Permissions.LocationWhenInUse>();

    if (status == PermissionStatus.Granted)
        return status;

    if (status == PermissionStatus.Denied && DeviceInfo.Platform == DevicePlatform.iOS)
    {
        // Prompt the user to turn on in settings
        // On iOS once a permission has been denied it may not be requested again from the application
        return status;
    }

    if (Permissions.ShouldShowRationale<Permissions.LocationWhenInUse>())
    {
        // Prompt the user with additional information as to why the permission is needed
    }

    status = await Permissions.RequestAsync<Permissions.LocationWhenInUse>();

    return status;
}

Estender permissões

A API de Permissões foi criada para ser flexível e extensível para aplicativos que exigem mais validação ou permissões que não estão incluídas no .NET MAUI. Crie uma classe que herda de Permissions.BasePermission e implemente os métodos abstratos necessários. O código de exemplo a seguir demonstra os membros abstratos básicos, mas sem implementação:

public class MyPermission : Permissions.BasePermission
{
    // This method checks if current status of the permission.
    public override Task<PermissionStatus> CheckStatusAsync()
    {
        throw new System.NotImplementedException();
    }

    // This method is optional and a PermissionException is often thrown if a permission is not declared.
    public override void EnsureDeclared()
    {
        throw new System.NotImplementedException();
    }

    // Requests the user to accept or deny a permission.
    public override Task<PermissionStatus> RequestAsync()
    {
        throw new System.NotImplementedException();
    }

    // Indicates that the requestor should prompt the user as to why the app requires the permission, because the
    // user has previously denied this permission.
    public override bool ShouldShowRationale()
    {
        throw new NotImplementedException();
    }
}

Ao implementar uma permissão de uma plataforma específica, a classe Permissions.BasePlatformPermission pode ser herdada. Essa classe fornece métodos auxiliares adicionais de plataforma para verificar automaticamente as declarações de permissão. Isso ajuda ao criar permissões personalizadas que fazem agrupamentos, por exemplo, solicitando acesso tanto para leitura quanto para gravação ao armazenamento no Android. O exemplo de código a seguir demonstra a solicitação de acesso de leitura e gravação ao armazenamento:

public class ReadWriteStoragePerms : Permissions.BasePlatformPermission
{
    public override (string androidPermission, bool isRuntime)[] RequiredPermissions =>
        new List<(string androidPermission, bool isRuntime)>
        {
        (global::Android.Manifest.Permission.ReadExternalStorage, true),
        (global::Android.Manifest.Permission.WriteExternalStorage, true)
        }.ToArray();
}

Em seguida, verifique a permissão da mesma forma que qualquer outro tipo de permissão fornecido pelo .NET MAUI:

PermissionStatus status = await Permissions.RequestAsync<ReadWriteStoragePerms>();

Se você quiser chamar essa API do código multiplataforma, poderá criar uma interface e registrar a permissão personalizada como uma dependência no contêiner de serviço do aplicativo. O exemplo a seguir mostra a interface IReadWritePermission:

public interface IReadWritePermission
{        
    Task<PermissionStatus> CheckStatusAsync();
    Task<PermissionStatus> RequestAsync();
}

Em seguida, implemente a interface em sua permissão personalizada:

public class ReadWriteStoragePermission : Permissions.BasePlatformPermission, IReadWritePermission
{
    public override (string androidPermission, bool isRuntime)[] RequiredPermissions => new List<(string androidPermission, bool isRuntime)>
    {
        (Android.Manifest.Permission.ReadExternalStorage, true),
        (Android.Manifest.Permission.WriteExternalStorage, true)
    }.ToArray();
}

Na classe MauiProgram, você deve registrar a interface e seu tipo concreto, e o tipo que consumirá a permissão personalizada, no contêiner de serviço do aplicativo:

builder.Services.AddTransient<MyViewModel>();
builder.Services.AddSingleton<IReadWritePermission, ReadWriteStoragePermission>();

A implementação de permissão personalizada pode então ser resolvida e invocada de um de seus tipos, como um viewmodel:

public class MyViewModel
{
    IReadWritePermission _readWritePermission;

    public MyViewModel(IReadWritePermission readWritePermission)
    {
        _readWritePermission = readWritePermission;
    }

    public async Task CheckPermissionAsync()
    {
        var status = await _readWritePermission.CheckStatusAsync();
        if (status != PermissionStatus.Granted)
        {
            status = await _readWritePermission.RequestAsync();
        }
    }
}

Diferenças de plataforma

Esta seção descreve as diferenças específicas de cada plataforma com a API de permissões.

As permissões devem ter os atributos correspondentes definidos no arquivo de Manifesto do Android. O status de permissão é definido por padrão como Denied.