Consumindo Web Service em aplicações Android

Publicado por Ricardo Ushisima
30/3/2011
Categoria:
Tags: , , ,

O SDK do Android não oferece uma solução fácil e embutida para consumir web services. Neste artigo, vou demonstrar como consumir web service usando a biblioteca KSOAP2.

Vou usar o Web Service que criei no meu artigo Expondo POCO como Web Services usando Spring Framework para criar uma aplicação de conversão de moedas feitas para dispositivos Android.

Só para lembrar, segue a interface do meu web service, que foi desenvolvido em .NET:

using System;

namespace SpringTutorial
{
    public interface ICurrencyService
    {
        decimal Convert(string from, string to, decimal value);
    }
}

Primeiro, vou implementar o serviço de conversão que irá consumir o web service de conversão de moedas desenvolvido anteriormente. O KSOAP2 é uma biblioteca que permite o consumo de web services sem a necessidade de geração de código ou uso de proxies dinâmicos. Lembre-se que a aplicação vai rodar em um dispositivo móvel e proxy dinâmico é um recurso caro computacionalmente.

package br.com.zbra.android.sample;

import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapPrimitive;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;

public class ConvertService {
	private static final String SOAP_ACTION = "http://zbra.com.br/springtutorial/Convert";
	private static final String METHOD_NAME = "Convert";
	private static final String NAMESPACE = "http://zbra.com.br/springtutorial";
	private static final String URL = "http://192.168.10.103/SpringTutorialService/CurrencyServiceWS.asmx";

	public String Convert(String fromCurrency, String toCurrency, String amount) {
		SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
		request.addProperty("from", fromCurrency);
		request.addProperty("to", toCurrency);
		request.addProperty("value", amount);

		SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
		envelope.dotNet = true;
		envelope.setOutputSoapObject(request);
		try {
			HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
			androidHttpTransport.call(SOAP_ACTION, envelope);
			SoapPrimitive result = (SoapPrimitive) envelope.getResponse();
			return result.toString();
		} catch (Exception e) {
			return e.getMessage();
		}
	}
}

O request é feito usando um SoapObject e cada parâmetro da chamada é uma propriedade do SoapObject. A chamada ao servidor de aplicações é feita usando um HttpTransportSE passando um envelope SOAP com a request gerada. Após a execução do serviço, o envelope irá conter o retorno do serviço. No nosso caso, o resultado é um decimal que é serializado como um SoapPrimitive seguindo o protocolo. Se o retorno fosse um objeto complexo, o retorno seria um SoapObject.

Tendo o serviço implementado, é só chamá-lo no Activity da aplicação Android:

package br.com.zbra.android.sample;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Spinner;

public class Main extends Activity {

	private Spinner fromCurrencySpinner;
	private Spinner toCurrencySpinner;
	private EditText amountEdit;
	private EditText resultEdit;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		bindControls();
	}

	private void bindControls() {
		fromCurrencySpinner = (Spinner) findViewById(R.id.from_currency_edit);
		toCurrencySpinner = (Spinner) findViewById(R.id.to_currency_edit);
		amountEdit = (EditText) findViewById(R.id.amount_edit);
		resultEdit = (EditText) findViewById(R.id.result_edit);
	}

	public void onConvertBtnClick(View v) {
		String fromCurrency = (String) fromCurrencySpinner.getSelectedItem();
		String toCurrency = (String) toCurrencySpinner.getSelectedItem();
		String amount = amountEdit.getText().toString();
		ConvertService service = new ConvertService();
		String result = service.Convert(fromCurrency, toCurrency, amount);
		resultEdit.setText(result);
	}
}

No arquivo AndroidManifest.xml, é necessário dar permissão para a aplicação poder acessar a internet.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
	package="br.com.zbra.android.sample" android:versionCode="1"
	android:versionName="1.0">
	<uses-sdk android:minSdkVersion="8" />
	<uses-permission android:name="android.permission.INTERNET"></uses-permission>
	<application android:icon="@drawable/icon" android:label="@string/app_name">
		<activity android:name=".Main" 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>

Por restrições de espaço e por não ser o escopo do artigo, vou apenas publicar um screenshot da minha aplicação de exemplo.

Vale observar que o consumo de Web Services em dispositivos móveis não é recomendado pela equipe de desenvolvimento do Android devido ao overhead que o processamento do SOAP exige. Se você tem controle sobre o servidor, o ideal é usar arquiteturas baseadas em REST tal como ODATA.

Referencias:

41 Comentários

  • Reply

    Por Luiz em 20 de September de 2011 às 20:58

    Olá Ricardo, interessante a biblioteca KSOAP2. Vou utiliza-la em alguns exemplos e curiosidades que descobrir compartilho aqui no ZBRA.

  • Reply

    Por Renato em 4 de November de 2011 às 15:56

    Estou desenvolvendo uma aplicação e nela eu tenho que buscar um objeto com vários parametro, ex: nome, idade, cpf, endreço. Eu quero apenas mostrar o nome da pessoa, como eu devo fazer? O xml de retorno tem que ter um padrão (header, body) e etc?

  • Reply

    Por joab silveira em 21 de February de 2012 às 13:46

    Opa ricardo, to com um probleminha
    fiz um web service simple com um webmethod que recebe dois parametros

    namespace SmartPDVSinc
    {
    ///
    /// Summary description for Service
    ///
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]

    public class Service : System.Web.Services.WebService
    {
    [WebMethod]
    public string mensagem(string primeironome, string segundonome)
    {
    return “nome completo ” + primeironome + ” ” + segundonome;
    }
    }
    }

    na minha aplicacao android coloquei da seguinte maneira

    public class LocalService {
    private static final String SOAP_ACTION = “http://tempuri.org/mensagem”;
    private static final String METHOD_NAME = “mensagem”;
    private static final String NAMESPACE = “http://10.0.2.2:45120″;
    private static final String URL = “http://10.0.2.2:45120/Service.asmx”;

    public String mensagem(String primeironome, String segundonome) {
    SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
    SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
    //envelope.dotNet = true;
    envelope.setOutputSoapObject(request);
    request.addProperty(“primeironome”, primeironome);
    request.addProperty(“segundonome”, segundonome);

    try {
    HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
    androidHttpTransport.call(SOAP_ACTION, envelope);
    SoapPrimitive result = (SoapPrimitive) envelope.getResponse();
    return result.toString();
    } catch (Exception e) {
    return e.getMessage();
    }
    }
    }

    no entando os parametros primeironome e segundo nao chegam ao webservice
    a mensagem retornada eh sempre “nome completo ” sem os valores passados nos parametros

    desde ja agradeco
    abraco

    • Reply

      Por Ricardo Ushisima em 2 de March de 2012 às 19:38

      Joab,
      vc verificou se a aplicação android esta realmente passando os parametros para o seu serviço?
      Por que vc comentou a linha envelope.dotNet = true; sendo que vc esta acessando um WS feito em .NET?
      Vc verificou se mensagem gerada pelo kSOAP tem os valores corretos? (use http://www.fiddler2.com para interceptar o pacote).

      Ricardo

  • Reply

    Por Rodrigo Dapper em 12 de March de 2012 às 17:44

    Ricardo, boa tarde, tudo certo.

    eu estou com dificuldades de conseguir enviar um xml da minha aplicação para um webservice, o arquivo é pequeno com poucas informações. mas estou com muitas dificuldades, por favor, será que consegue me ajudar. desde já obrigado.

    • Reply

      Por Ricardo Ushisima em 19 de March de 2012 às 12:13

      Oi Rodrigo,
      preciso de mais informação para tentar ajudar no seu problema.

  • Reply

    Por Jefferson em 22 de March de 2012 às 17:25

    Saudações…
    Consegui consumir um ws .asmx com sucesso. Mas com um ws WCF .svc não virou. Vc sabe se é possivel acessa-lo pelo ksoap2?

    • Reply

      Por Ricardo Ushisima em 23 de March de 2012 às 11:46

      Sim, é possível consumir serviços WCF desde que o binding WCF seja do tipo BasicHttp. Se o serviço usa DataContracts, o xml gerado no corpo do SOAP Request é um pouco diferente. Se usa Message Contract, o xml deve ser o mesmo. Use o Fiddler (http://www.fiddler2.com/) para inspecionar a troca de xml e montar o SOAP Object no Android de maneira apropriada.

  • Reply

    Por felipe Bonatto em 6 de April de 2012 às 20:19

    Olá Ricardo tudo bem? Estou com problemas para consumir um webservice em Axis2. Fiz todos os procedimentos mas na hora do androidHttpTransport.call() ele ja pula para o meu catch. Estou vendo as passagens de valores e aparentemente estão corretos. Coloquei a mensagem do e.getMessage() e ele retorna “Cannot serialize: “valor”.

    • Reply

      Por Ricardo Ushisima em 9 de April de 2012 às 16:41

      O valor é um decimal? Esta no formato decimal correto (separado por ponto)?

      • Reply

        Por felipe Bonatto em 9 de April de 2012 às 18:53

        Opa Ricardo, então eu finalmente consegui consumir, porém percebi que para tipos double e float ele vai com “10.0″ por exemplo, eu devo tratá-lo antes?

        • Reply

          Por Ricardo Ushisima em 12 de April de 2012 às 15:08

          Não deveria ser necessário tratar os números antes.

  • Reply

    Por Bruno Ap em 15 de April de 2012 às 18:22

    Boa tarde Ricardo , seria possivel enviar um array de tipos primitivos para o webservice em request.addProperty()?

    Por exemplo

    String [] valores ={“a”,”b”};

    request.addProperty(“parametro”, valores)

  • Reply

    Por Fabiano em 1 de May de 2012 às 12:01

    Olá Ricardo, tenho uma dúvida, como eu faço para testar o webservice, é o seguinte eu tenho o aplicativo em android quero fazer uma consulta dos dados via WS, como que eu faço para deixar esse serviço disponivel no meu computador local? já tenho o ip da minha maquina que vai levantar o serviço e o celular esta na mesma rede.. como eu faço isso?

    • Reply

      Por Bruno Vinicius em 22 de May de 2012 às 15:30

      Fabiano, se eu entendi bem, você não consegue acessar o seu computador a partir do EMULADOR. Nesse caso, existe um IP especifico que faz com que o emulador (que é na verdade uma máquina virtual) acesse o PC (localhost): 10.0.2.2.

  • Reply

    Por Adriano Spolidori em 22 de May de 2012 às 9:14

    Bom dia Ricardo…muito bom o tópico, porém somente consigo executar o aplicativo pelo emulador. Quando instalo o apk no celular (android 2.3.4) ele nem inicializa o aplicativo (já dispara o fechamento forçado). Reparei que o aplicativo instalado no celular não possui nenhum tipo de permissão, porém indiquei no manifest a permissão de acesso à internet. Grato

    • Reply

      Por Ricardo Ushisima em 22 de May de 2012 às 19:45

      Seu aplicativo deve estar lançando um Exception e abortando a aplicação. Toda exceção não tratada lançada pela aplicação força o fechamento dela.

  • Reply

    Por Joao em 14 de June de 2012 às 16:08

    Ola Ricardo eu fiz um exemplo de consumir um web service axis porem quando inicializo o aplictivo sempre vem esta mensaguem
    06-14 19:05:18.146: ERROR/dalvikvm(340): Could not find class ‘org.ksoap2.serialization.SoapObject’, referenced from method br.consome.dsoft.ConsomewebserviceActivity.clicarWS
    ja me matei de procurar e nada nao consigo fazer nada no web service
    poderia me dar uma ajuda

    Obrigado

    • Reply

      Por Bruno Vinicius em 14 de June de 2012 às 16:58

      Joao, você precisa colocar o jar do ksoap no diretório “libs” do seu projeto, caso contrário ele não vai ser incluso no APK gerado. Assegure-se que o diretório chama-se “libs” e não “lib”, normalmente é esse o problema.

  • Reply

    Por William em 4 de July de 2012 às 11:35

    Bom dia,

    Estou com um grande problema em autenticar o usuário. Quando o mesmo for baixar as informações do WebServices o aparelho vai enviar o seu UNIQUE ID e vai criar uma Sessão no servidor. O aplicativo teria que usar essa sessão para poder baixar todas informações.

    Você conhece algo?

    • Reply

      Por Ricardo Ushisima em 10 de July de 2012 às 19:18

      A sessão com o servidor geralmente é mantida por meio de Cookies.
      Em ASP.NET por exemplo, o servidor retorna um cabecalho HTTP com o identificador da sessão:
      “Set-Cookie: ASP.NET_SessionId=msnlhdauahrkw3l5ioo4hqtv;”

      Basta repetir esse mesmo cabeçalho nas requisições subsequentes para reusar a mesma sessão.

  • Reply

    Por Carlos Alberto em 29 de July de 2012 às 16:23

    Ricardo, boa tarde! montei um web service em asp.net que efetua cálculos matemáticos, só que ele esta me retornando acesso negado, e estou utilizando as permissões do android:

    O que fazer?

    • Reply

      Por Ricardo Ushisima em 1 de August de 2012 às 16:05

      Você precisa saber primeiro quem esta negando acesso. Seu web service ou o android (permissão para acessar internet). Use o Fiddler2 (http://www.fiddler2.com/fiddler2/) para inspecionar a comunicação entre o android e seu serviço.

  • Reply

    Por Oliver em 27 de November de 2012 às 14:10

    Boa tarde Ricardo!

    Primeiramente, parabens pelo Tutorial! Está muito bacana!

    Estou com uma dificuldade ao executar meu webservice via android. Continuamente recebo a mensagem
    “cannot find dispatch method for”.
    Chequei o NAMESPACE, SOAP_ACTION, METHOD_NAME e URL e parecem estar todos corretos. Tem alguma outra sugestão do que pode ser o problema (se vc quiser, posso enviar partes dos códigos aqui).

    Obrigado

  • Reply

    Por Adriano Boller em 3 de January de 2013 às 8:55

    Ola Ricardo,

    eu estou com uma dificuldade em um aplicativo android, codigo:

    sHTMLCode is string = HTTPRequest(“http://www.viajasantuarios.com.br/webservice/ws.asmx/ConsultaReservaPedido?IdWS=TESTE_WS_VITALCARD&CodSite=1&SenhaVoucher=VRVRPRDCXP&TpoRetorno=HTML&CodReservaPedido=”)
    Info(“The HTML code is: ” + sHTMLCode)
    Info(HTTPGetResult())
    Info(UTF8ToString(HTTPGetResult()))
    HTTP_Res is string = UTF8ToString(HTTPGetResult())
    IF HTTP_Res = “” then
    info(“Vazio”)
    ELSE
    info(“OK”)
    END

    Não da ok, da erro code 500!…

    Agora se eu colocar um link de um site: http://www.uol.com.br da ok

    sHTMLCode is string = HTTPRequest(“http://www.uol.com.br”)
    Info(“The HTML code is: ” + sHTMLCode)
    Info(HTTPGetResult())
    Info(UTF8ToString(HTTPGetResult()))
    HTTP_Res is string = UTF8ToString(HTTPGetResult())
    IF HTTP_Res = “” then
    info(“Vazio”)
    ELSE
    info(“OK”)
    END

    Existe alguma diferença de leitura no xml e no http?

  • Reply

    Por Jaini em 7 de January de 2013 às 12:38

    Boa Tarde… segui o seu tutorial, fui alterando para as variaveis que preciso, no caso eram 3 edit text,2 para inserir numeros e mais 1 para trazer o resultado e um botao para calcular, fiz como no seu código. Só que ao clicar no botão, ele não faz nada… ou seja, nao tem ação. Mas está de conforme o seu código. Pode me dar alguma dica neste caso?
    Desde já, muito obrigada.

  • Reply

    Por Lucas em 22 de February de 2013 às 15:31

    Olá!

    Sou super iniciante em Android e WebServices,
    Estou com problemas na hora de definir o SOAP_ACTION e o NAMESPACE do meu WebService Apache+Axis+Java…

    Tenho o serviço rodando perfeitamente quando utilizo por método Get no navegador.

    Porém, no meu Android App, não estou conseguindo retornar valor algum. Acredito que o WebService nem esteja sendo acessado.
    Já que não há nada nas constantes SOAP_ACTION e NAMESPACE da minha aplicação, que utilizei código que você publicou aqui.

    Grato.

    • Reply

      Por Ricardo Ushisima em 20 de March de 2013 às 17:58

      SOAP_ACTION e NAMESPACE podem ser encontradas no WSDL do seu Web Service.

  • Reply

    Por Rômulo Nadler em 4 de June de 2013 às 15:50

    Poderia me ajudar na autentiação do usuário, o meu webservice em .NET esta pedindo um usuário e senha, como faço para validar via android?

    • Reply

      Por Ricardo Ushisima em 11 de June de 2013 às 15:02

      Se o IIS estiver configurado como Basic Authentication, você pode tentar usar HttpTransportBasicAuth ao inves do HttpTransportSE. Se estiver configurado como Windows Authentication (NTLM), o kSoap não suporta.

  • Reply

    Por Rafael em 2 de July de 2013 às 2:11

    Boa noite Ricardo, primeiramente gostaria de parabenizar o seu post, que me ajudou muito. Estou com uma dúvida de como passar objetos nessas situações, sendo que eu os tenho mapeado no web service (c#) e na minha aplicação android. O parâmetro do meu webmethod é o objeto. Obrigado !

  • Reply

    Por Ricardo Sutana em 17 de July de 2013 às 20:09

    Olá Ricardo
    Estou tentando receber um objeto vindo de um webservice mas nao sei como fazer isso usando a lib ksoap2 v3.0.0, se puder me ajudar…
    Este é o método de busca que estou usando dentro do meu webservice:
    public Coordenada buscaUma (int nimei) throws SQLException{

    Coordenada tupla = null;

    return tupla;
    }
    No android eu criei uma classe CoordenadaBean que possui os mesmos tipos da minha classe coordenada no webservice.
    Tambem tenho a classe WSConnection a qual é responsavel por fazer a chamada do webservice, mas nao sei como receber este objeto vindo do meu web service, para depois exibi-lo nos textview do andoid.

    Obrigado att

  • Reply

    Por paulo em 22 de July de 2013 às 23:13

    Ola Bruno, estou querendo enviar um texto para o mysql e mostrar o resultado na minha aplicação, poderia me ajudar?

  • Reply

    Por Djair em 24 de October de 2013 às 13:57

    boa tarde estou construindo uma aplicação e precisarei consumir serviços de webservices cujo o servidor será o glassfish, estou usando axis2, ksoap2.
    segui os passos desse tutorial so que apenas recebo como resposta “HTTP request failed, HTTP status: 500″ para usar o servidor glassfish é necessário fazer alguma configuração à mais, diferentemente do TOMCAT

  • Reply

    Por Fabio A. Falavinha em 6 de December de 2013 às 9:58

    Oi Djair, você consegue acessar a URL via browser para expor o WSDL? Se você conseguir receber o WSDL, sugiro que você utilize a ferramenta soapUI para poder acessar o seu WSDL e gerar classes de testes, pela ferramenta, para verificar o uso do seu serviço.
    Envie a stack trace completa da exception que você está recebendo.

  • Reply

    Por Ricardo Fagmer em 19 de June de 2014 às 19:23

    Olá pessoal não consigo acessar o webservice no qual mando usuario e senha e ele me retorna 0 ou 1;

    Erro:
    at org.ksoap2.transport.ServiceConnectionSE.connect(Unknown Source)

    Debugando ele para na linha
    androidHttpTransport.call(SOAP_ACTION, envelope);

  • Reply

    Por Desentupimento em 10 de November de 2014 às 23:28

    bem esclarecedor !





Desenvolvido por hacklab/ com WordPress