Android

12 set, 2018

Concessão de permissões em tempo de execução no Android com Dexter

Publicidade

Anteriormente, ao realizar a instalação de aplicativos em um dispositivo com sistema Android, havia a necessidade de que no momento anterior à instalação, o usuário concedesse permissão de acesso a todos os recursos indispensáveis à execução do aplicativo, como o acesso a câmera, armazenamento, localização, entre outros.

Porém, após o lançamento do Android Marshmallow, foi introduzido o sistema de concessão de permissões em tempo de execução, onde este tinha por objetivo possibilitar ao usuário autorizar ou revogar qualquer acesso por parte de aplicações aos recursos do seu Android.

A intenção desta mudança foi estabelecer ao usuário maior controle sobre os recursos do seu dispositivo, possibilitando-o, por exemplo, conceder a um aplicativo que necessita dos recursos de câmera e localização, que tenha somente acesso à câmera, porém não a sua localização.

Tratando-se da implementação das solicitações de permissão em projetos Android, este processo torna-se um tanto quanto tedioso e o desenvolvedor precisa se recordar de várias funções com inúmeras linhas de código, sendo que em certos momentos apenas necessita obter uma única permissão.

Levando em consideração este fato, abordaremos a utilização da biblioteca Dexter, a qual possibilita implementar a concessão de permissões em tempo de execução de forma simples, com a estrutura de métodos bem organizada e código com boa legibilidade em alguns minutos. Abaixo demonstramos a composição estrutural básica na utilização desta biblioteca:

Dexter.withActivity(actvity)
        .withPermission(Manifest.permission.RECURSO_SOLICITADO)
        .withListener(new PermissionListener() {
                public void onPermissionGranted(PermissionGrantedResponse response)

                    {/* ... */}
                public void onPermissionDenied(PermissionDeniedResponse response)    

                    {/* ... */}
                public void onPermissionRationaleShouldBeShown(PermissionRequest    

              permission, PermissionToken token)

                    {/* ... */}
        }).check();

Para solicitar as permissões necessárias utilizando o Dexter, deve-se descrever o recurso solicitado utilizando o método withPermission() passando para a função a referência do recurso requerido, lembrando que o Dexter possibilita solicitar múltiplas permissões utilizando o método withPermissions(). Precisamos, também, de um retorno de chamada do tipo PermissionListener() para receber o estado da permissão, ou seja, se a mesma foi concedida ou revogada. Abaixo uma breve explicação de cada método:

  • onPermissionGranted(): este método será chamado quando a permissão ao recurso for concedida, possibilitando exercer uma ação específica.
  • onPermissionDenied(): será invocado caso a permissão ao recurso for revogada. Podemos verificar se a permissão foi negada permanentemente utilizando a condição RESPOSTA.isPermanentlyDenied() que, se for o caso, podemos implementar o acesso às configurações do aplicativo para que o usuário altere-as manualmente.
  • onPermissionRationaleShouldBeShown(): neste método é configurado a utilização de um token pelo Dexter, a fim de que ele não inicie o processo de concessão novamente sem haver finalizado completamente.

Implementação

Primeiramente é necessário incluir a biblioteca do Dexter no arquivo build.gradle:

dependencies {
        // Dexter: Permissões em tempo de execução   

     implementation 'com.karumi:dexter:4.2.0'
}

Lembre-se de adicionar as permissões solicitadas no arquivo AndroidManifest.xml do seu projeto como de costume.

Solicitando Permissão Única

Para solicitar uma única permissão, utilizamos o método withPermission(), onde neste exemplo passamos a referência para permissão de utilização da câmera do dispositivo.

Dexter.withActivity(this)

      .withPermission(Manifest.permission.CAMERA)

      .withListener(new PermissionListener() {

            @Override

            public void onPermissionGranted(PermissionGrantedResponse response){

                    // permissão concedida, abre a câmera

            }

            @Override

            public void onPermissionDenied(PermissionDeniedResponse response){

                  // permissão negada, checa se foi negado permanente,

                  // para abrir tela de configuração do aplicativo

                  if (response.isPermanentlyDenied()) {

                        // abre a tela de configuração do app

                  }

            }

            @Override

            public void onPermissionRationaleShouldBeShown(PermissionRequest permission, PermissionToken token){

                  token.continuePermissionRequest();

            }

      }).check();

Solicitando Múltiplas Permissões

Para solicitar várias permissões em meio a execução do aplicativo, utilizamos o método withPermissions(). No exemplo abaixo solicitamos permissão aos recursos STORAGE e LOCATION.

Dexter.withActivity(this)
    .withPermissions(            

          Manifest.permission.READ_EXTERNAL_STORAGE,
         Manifest.permission.WRITE_EXTERNAL_STORAGE,
         Manifest.permission.ACCESS_FINE_LOCATION)
    .withListener(new MultiplePermissionsListener() {
         @Override
         public void onPermissionsChecked(MultiplePermissionsReport report){
              // checa todas as permissões foram concedidas
               if (report.areAllPermissionsGranted()) {
                   // ação exercida após verificação
               }
              // permissão negada, checa se foi negado permanente,

               // em algum recurso solicitado

               if (report.isAnyPermissionPermanentlyDenied()) {
                  // abre a tela de configuração do app
              }
         } 
         @Override
         public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {
              token.continuePermissionRequest();
         }
    }).onSameThread()
      .check();

Manipulação de Erros

Em relação a ocorrência de possíveis erros na integração do Dexter com o projeto Android, é possível identificá-los utilizando a função PermissionRequestErrorListener() conforme demonstrada no exemplo abaixo:

Dexter.withActivity(this)

     .withPermissions(

          Manifest.permission.READ_EXTERNAL_STORAGE,

          Manifest.permission.ACCESS_FINE_LOCATION)

     .withListener(listener)

     .withErrorListener(new PermissionRequestErrorListener() {

          @Override

          public void onError(DexterError error) {

               // Caso ocorram erros

               Toast.makeText(getApplicationContext(), "Ocorreu um erro:( !! " + error.toString(), Toast.LENGTH_SHORT).show();

          }

     }).check();

Conclusão

É isso aí, pessoal! Com a utilização desta biblioteca sua produtividade e organização do seu código será 100%. Você pode conferir neste link um exemplo de projeto com a implementação desta biblioteca onde demonstrei um pedido de solicitação de permissão única e de múltiplas solicitações.

Referências