quarta-feira, 29 de abril de 2015

Como consumir webservice SOAP no Android

Embora não haja suporte nativo para o consumo de webServices SOAP no Android (e também não seja uma prática recomendada pela Google), é possível fazê-lo.

Há uma infinidade de serviços online que utilizam o protocolo SOAP . Também, um grande número de empresas investiram tempo (e dinheiro) construindo conjuntos de serviços baseados nele.

Sendo assim, surgiu a necessidade de consumir SOAP em aplicativos Android. E, para nossa sorte, alguém um dia acordou inspirado e resolveu desenvolver uma biblioteca gratuita que permite fazer exatamente isso. Chama-se:  KSOAP2 Library.

Este tutorial ensina a consumir um webService SOAP em um aplicativo Android.

Para começar, vamos escolher o serviço online que será consumido como exemplo. Utilizaremos um webService simples, de conversão de temperaturas, disponível  no endereço abaixo:




O primeiro passo é descobrir quais os métodos disponíveis nesse webService, isto é, quais as operações que podemos executar a partir do consumo.

A pior maneira de fazer isto é abrindo o endereço acima no navegador e tentando descobrir através da leitura do WSDL. Uma maneira mais fácil é usar o software SoapUI, que já está disponível na pasta "@Android\Ferramentas" do nosso ambiente de desenvolvimento.


Vamos abrir o SoapUI e selecionar o menu "File", opção "New SOAP Project", para criar um novo projeto, conforme a figura:







Surgirá uma caixa de diálogo pedindo o nome do projeto e a localização do arquivo WSDL, que é o descritor do webservice. É exatamente o que vamos precisar colar neste campo:
http://www.w3schools.com/webservices/tempconvert.asmx?wsdl.
O nome do projeto aparecerá automaticamente. Depois, basta pressionar o botão "OK".







O SoapUI interpretará o WSDL para nós, identificando os métodos disponíveis existentes no serviço. Na parte superior esquerda da janela principal, ele desenhará uma árvore representando os serviços e seus métodos que poderemos utilizar:






O que nos interessa para efeito deste tutorial é o método "CelsiusToFarenheit", que converte uma temperatura em graus Celsius em seu valor correspondente em Farenheit. Agora, portanto, vamos clicar duas vezes na opção "Request 1". Abrirá uma janela onde poderemos efetuar um consumo real do serviço. Para isso, precisaremos preencher os argumentos que o método exige como obrigatórios. Neste caso é bastante intuitivo: O método pede que especifiquemos o valor da temperatura em graus Celsius. Vamos digitar "32". Depois, precisaremos clicar no botão de "play", no canto superior esquerdo da janela, para que o SoapUI realize a requisição. O resultado do consumo será mostrado à direita, na janela, que apresentará a temperatura convertida em Farenheit, conforme imagem:








Ok! Cumprimos a primeira tarefa. Selecionamos um serviço online e, com a ajuda do SoapUI, conseguimos determinar o método que nos interessa (CelsiusToFarenheit) e seu argumento (Celsius). Precisaremos ainda do "namespace" do serviço, pois será necessário informá-lo ao KSOAP2. Para obter o namespace, basta, no SoapUI, clicar duas vezes sobre o nome do serviço, então uma janela com o namespace será mostrada, conforme a imagem:









Pronto! Já temos agora todo o necessário para iniciar um projeto de consumo do serviço SOAP pelo Android.

Vamos então criar um projeto no nosso ambiente de desenvolvimento chamado "consumidorSoap". O primeiro passo é incluir no projeto o arquivo JAR da biblioteca KSOAP2, que pode ser baixado clicando-se aqui. Se preferir obter uma versão mais recente, baixe diretamente do site do projeto KSOAP2, citado no início deste post.

Este arquivo deve ser colocado na pasta LIBS do projeto, conforme imagem:







O passo seguinte é criarmos o método que consome o serviço:


   // Método que consome o webService.
   public double converterCelsiusParaFarenheit(double grausCelsius)
   {
      
      // Define variável para armazenar o resultado.
      double resultado=-1;
      
      // Define o namespace, a URL do endpoint, e a ação do webService.
      String NAMESPACE="http://www.w3schools.com/webservices/";
      String URL = "http://www.w3schools.com/webservices/tempconvert.asmx?wsdl";       
      String END_POINT="http://www.w3schools.com/webservices/";     
      String METHOD_NAME="CelsiusToFahrenheit";                                     
      String SOAP_ACTION=END_POINT + METHOD_NAME;                            
            
      // Define quantos milissegundos o KSOAP2 aguardará antes de considerar que a requisição falhou.
      int timeout=20000;
      
      // Declarações das variáveis necessárias para criar a requisição e transportá-la.
      HttpTransportSE ht;
      SoapObject request;
      
      // Cria a requisição SOAP, para consumir o webService.
      request=new SoapObject(NAMESPACE, METHOD_NAME);    
      
      // Cria o envelope.
      SoapSerializationEnvelope envelope=new SoapSerializationEnvelope(SoapEnvelope.VER11);
      envelope.dotNet = true;
      
      // Acrescenta o parâmetro ao argumento do webService.
      request.addProperty("Celsius", String.valueOf(grausCelsius));
            
      // Insere a requisição montada no envelope.
      envelope.setOutputSoapObject(request);
      
      // Define o objeto que efetuará o transporte. Aqui também é definido o timeout.
      ht=new HttpTransportSE(Proxy.NO_PROXY, URL, timeout);

      try
      {
         // Efetivamente chama o consumo do webService.
         ht.call(SOAP_ACTION, envelope);
         
         // Extrai os elementos da resposta do webService.
         String rs = "" + envelope.getResponse(); 
         resultado=Double.parseDouble(rs);

      }
      catch (Exception e)
      {
         // Caso tenha ocorrido algum problema, indica a mensagem de erro no LogCat.
         Log.i("consumidorSoap", "(MainActivity, método converterCelsiusParaFarenheit) erro: " + e.toString());
      }

      // Limpa os objetos instanciados, para liberar memória.
      request=null;
      envelope=null;
      ht=null;

      // Retorna o resultado.
      return resultado;
   }


A rotina acima consumirá o webService SOAP chamando o método remoto "CelsiusToFarenheit", passando um valor em graus Celsius e recebendo de volta uma resposta com o valor convertido em Farenheit.

Copie e cole o método na classe MainActivity.java.

Agora vamos criar a chamada ao método:

Primeiro vamos definir as variáveis, logo antes do método onCreate():

   // Define as variáveis que guardarão os valores das temperaturas.
   private Double temperaturaEmFarenheit;
   private Double temperaturaEmCelsius;

   private String mensagem="";


Depois, no próprio método onCreate(), logo após o "setContentView", vamos adicionar o código:

    // Chama o método para consumir o webService que converte de Celsius para Farenheit.
    temperaturaEmCelsius=32.0;
    temperaturaEmFarenheit = converterCelsiusParaFarenheit(temperaturaEmCelsius);

    // Define a mensagem de saída.
    if (temperaturaEmFarenheit > 0)
    {
       mensagem=temperaturaEmCelsius + "° Celsius = " + temperaturaEmFarenheit + "° Farenheit.";
    }
    else
    {
       mensagem="Não foi possível efetuar a conversão a partir do webService.";
    }
     
    // Mostra o resultado da conversão no LogCat.
    Log.i("consumidorSoap", mensagem);


O passo seguinte é acrescentar a permissão de uso de Internet ao arquivo AndroidManifest.xml, sem a qual ganharíamos erro:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.consumidorsoap"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />

    <uses-permission android:name="android.permission.INTERNET" />
    
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.consumidorsoap.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>


Também teremos que criar uma entrada no LogCat, a fim de visualizar as mensagens de debug advindas da execução do nosso código, pois não estamos mostrando nada na tela do dispositivo.

Basta selecionar o LogCat, na parte inferior central da janela do Eclipse e primeiro clicar no sinal de "+" verde. Na janela que se abre, digitar "consumidorSoap" nas duas primeiras linhas e depois clicar no botão "OK":





Pronto. Agora é só compilar o projeto e ver o resultado:







Quem preferir poderá baixar o código completo. É claro que este é um exemplo bem simples, consumindo um webService SOAP básico. Se for o caso do WSDL conter objetos complexos (complexTypes), a abordagem muda um pouquinho. Quem precisar de ajuda, estou à disposição. Ficamos por aqui. Espero que tenha sido proveitoso. Até o próximo post!

6 comentários:

  1. Boa tarde Luiz estou com erro ao executar um simples webservice (server) que fiz utilizando java. E ocorre o seguinte erro:android.os.NetworkOnMainThreadException .
    Meu WSDL:



















































    -------------------
    String NAMESPACE="http://192.168.15.50:9876/";
    String URL = "http://192.168.15.50:9876/guttyws?wsdl";
    String END_POINT="http://192.168.15.50:9876/";
    String METHOD_NAME="testar";
    String SOAP_ACTION=END_POINT + METHOD_NAME;

    ResponderExcluir
    Respostas
    1. Prezado, este é um erro muito comum no Android. Advém do fato de que você está tentando acessar a rede de dentro do MainActivity, de forma síncrona. No Android, você precisa acessar a rede de forma assíncrona, uma vez que não tem como saber quando receberá uma resposta. Você precisa colocar a chamada dentro de um Thread ou dentro de um AsyncTask. Aí vai funcionar!

      Excluir
  2. Olá Luiz! Muito boa a sua explicação.
    Estou tentando consumir um webservice com alguns tipos complexos e várias funções.
    Fazer "na mão", pelo que vi, é inviavel.
    Você conhece algum jeito automático de se criar essa interface entre o webservice e a aplicação Android?

    ResponderExcluir
  3. Olha... O KSoap tem algumas formas sofisticadas que permitem fazer isto, mas você teria que pesquisá-lo mais a fundo. Outra alternativa é utililar alguma linguagem que gere os STUBS do serviço, ou seja, você manda consumir o WSDL e ele gera as rotinas prontinhas pra você usar. Eu sei que o Java tem isso, ferramentas que geram os STUBS. Coldfusion também (pois funciona sobre Java). De posse desses stubs, você migra para o Android facilmente.

    ResponderExcluir
  4. Alex, pesquise no Google sobre WSIMPORT.

    ResponderExcluir