sexta-feira, 25 de fevereiro de 2011

Web Services no Android

Olá povo,

No artigo anterior, apresentei como criar Web Services com o Apache Axis2 no Eclipse EE com o plugin WTP. Nesse post mostrarei como acessar esse WebService através de uma aplicação Android.

Um ótimo framework para acessar web services é o KSOAP. Ele é bem conhecido dos desenvolvedores Java ME, uma vez que era a maneira mais fácil de se acessar web services em celulares MIDP. Vamos utiliza-lo no Android através da sua versão para Java SE. Ela pode ser obtida aqui.
Crie um novo projeto Android (que nomearei de BlogWSClient) e adicione o JAR ao projeto. Isso deve ser feito criando uma pasta chamada lib na raiz do projeto e copiando o JAR para lá. Em seguida, adicione esse JAR ao classpath do seu projeto.
Uma vez que iremos acessar um serviço Web, precisamos da permissão android.permission.INTERNET. Sendo assim, o próximo passo será adiciona-la ao nosso aplicativo através da tag uses-permission que deve ser adicionada ao nosso AndroidManifest.xml conforme abaixo.


<uses-permission android:name="android.permission.INTERNET"/>


Agora vamos para o código da nossa Activity. Não vou me preocupar com a parte da interface gráfica, vou apenas mostrar a utilização dos objetos KSOAP.
Tenha sempre esse princípio básico em mente: TODA comunicação de rede deve ser feita com uma Thread separada da Thread principal da aplicação.
Sendo assim, faremos com que nossa classe implemente a interface java.lang.Runnable e no método onCreate, criamos e inicializamos uma nova thread passando a própria instância da Activity como parâmetro. Com isso, o método run chamará dois métodos que, por sua vez, farão a requisição aos nossos serviços.

package ngvl.android.blogws;

// omiti os imports... :)

public class PrincipalActivity
extends Activity
implements Runnable {

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

new Thread(this).start();
}

public void run() {
chamaHelloWS();
chamaPessoaWS();
}

// Adicione os próximos métodos aqui
}

Agora vamos ver a chamada ao serviço HelloWS. Iniciamos com a criação de um SoapObject que representa o namespace do serviço e o método que queremos chamar. Isso está definido no WSDL do nosso serviço, procure pelas propriedades xml:ns e wsdl:operation respectivamente. Em seguida, passamos o parâmetro que o serviço requer, que no exemplo é o nome da pessoa. As requisições SOAP são feitas através de envelopes. Esse objeto é criado e atrelado ao primeiro que criamos.
A variável url armazena o caminho do nosso serviço. Observe que estamos utilizando o IP 10.0.2.2 que permite com que o emulador acesse a máquina local. Se você usa localhost estará tentando acessar o próprio emulador. No aparelho, você deve colocar o endereço real do seu servidor.
Feita a requisição, é só pegar a resposta a partir do envelope.


private void chamaHelloWS() {
SoapObject soap = new SoapObject(
"http://blogws.jee.ngvl", "digaOla");

soap.addProperty("nome", "glauber");

SoapSerializationEnvelope envelope =
new SoapSerializationEnvelope(SoapEnvelope.VER11);

envelope.setOutputSoapObject(soap);

Log.i("NGVL", "Chamando HelloWS");

String url =
"http://10.0.2.2:8080/BlogWS/services/HelloWS";

HttpTransportSE httpTransport =
new HttpTransportSE(url);

try {
httpTransport.call("", envelope);

Object msg = envelope.getResponse();

Log.i("NGVL", "Mensagem: " + msg);

} catch (Exception e) {
e.printStackTrace();
}
}


O método que acessa PessoaWS é bem similar ao anterior, o que muda é apenas a resposta, uma vez que não mais temos um só retorno, e sim uma lista deles. essa lista é obtida através da propriedade bodyIn do envelope. Então é só percorrer a lista que é retornada.


private void chamaPessoaWS() {
SoapObject soap = new SoapObject(
"http://blogws.jee.ngvl", "obterPessoas");

SoapSerializationEnvelope envelope =
new SoapSerializationEnvelope(SoapEnvelope.VER11);

envelope.setOutputSoapObject(soap);

Log.i("NGVL", "Chamando PessoasWS");

String url =
"http://10.0.2.2:8080/BlogWS/services/PessoaWS";

HttpTransportSE httpTransport =
new HttpTransportSE(url);

try {
httpTransport.call("", envelope);

SoapObject results =
(SoapObject) envelope.bodyIn;

int count = results.getPropertyCount();

for (int i = 0; i < count; i++) {
SoapObject obj = (SoapObject)results.getProperty(i);

Log.i("NGVL",
"Nome: "+ obj.getProperty("nome"));

Log.i("NGVL",
"Idade: "+ obj.getProperty("idade"));
}
} catch (Exception e) {
e.printStackTrace();
}
}


Bem pessoal, espero que vocês tenham gostado. Esse foi um post relâmpago :) dois numa noite só.

4br4ç0s,
nglauber

24 comentários:

Roger disse...

Works like a charm! parabéns pelo tutorial muito bom!!! vou criar uma interface agora pra incrementar!
abração!

Tiago disse...

nao estou a conseguir por a funcionar... como devo por as portas/ip para conseguir correr no meu smartphone?

Nelson Glauber de Vasconcelos Leal disse...

Oi Tiago,

O IP usado nesse exemplo foi estabelecido pelo Android para que o emulador consiga acessar a máquina local, pois, para o emulador, localhost é ele próprio.
Para você acessar o webservice a partir do aparelho real, você tem duas opções: 1) se webservice estiver na sua máquina local, você pode acessar via wi-fi colocando o IP da máquina na rede (ao invés do 10.0.0.2). Nesse contexto, verifique as configurações de firewall da máquina, pois às vezes elas barram esse tipo de conexão por padrão. 2) a outra opção é se o webservice estiver em um servidor real, aí é mais fácil, pode ser com 3G ou Wi-Fi aí é só colocar a URL do webservice no servidor.

4br4ç05,
nglauber

Anônimo disse...

Parabéns pelo post, muito bom e fácil de entender. Realmente funciona perfeitamente. No meu caso estou precisando de plotar os dados dentro de um listview, você tem ideia de como fazer isso? Muito obrigado

Nelson Glauber de Vasconcelos Leal disse...

Oi Anônimo,

Dá uma olhada nesse post que eu acho que vai te ajudar:
http://nglauber.blogspot.com/2011/03/adapter-eficiente-no-android.html

Você vai ter que pegar os dados vindos do WS e preencher com uma lista de objetos, depois você passa essa lista pro seu Adapter e daí preenche a lista.

4br4ç05,
nglauber

Renato disse...

Opa... Consegui fazer, buscar uma lista e setar no listview, porém eu utilizei o primeiro código (sem o for()), agora estou pensando se eu tenho vários retornos, exemplo: cod, idade, pessoa, cidade e quero mostrar apenas os nomes que foram retornados. Será se terei que adaptar o código do php que faz a comunicação com o webservice? Tem alguma ideia? abraço

Diego disse...

Opa, glauber, blz?
Cara, fiz igualzinho ao que você postou mas deu um erro

ClassCastException: org.ksoap2.SoapFault
O erro é na linha SoapObject results = (SoapObject) envelope.bodyIn. Tu sabes dizer o que eh?

Vlw

Nelson Glauber de Vasconcelos Leal disse...

Oi Diego,

Tem que ver como você fez o WebService. Pode ser que o seu WebService não esteja retornando uma Lista de Objetos e sim apenas um.

4br4ç05,
nglauber

Renato disse...

Lá no webservice é retornado uma lista de objetos então teoricamente eu teria que usar o segundo exemplo que você postou com o for() mas esse código não funcionou aqui, talvez fiz alguma coisa errada.

Diego disse...

É uma lista de objetos, pq eu fiz igualzinho na primeira parte tb,a de ObterPessoas(que retorna uma lista de pessoas), só que com outra classe.

renato disse...

Glauber, tem como você posta o xml que você está usando? Só para conferir se o que eu tenha está do jeito certo para utilizar o código que você postou. abraço

Nelson Glauber de Vasconcelos Leal disse...

Oi Renato,

O webservice que eu estou acessando está nesse outro post: http://nglauber.blogspot.com/2011/02/web-service-com-apache-axis-14.html

4br4ç05,
nglauber

Anônimo disse...

VC EH FERA!

João Paulo disse...

esse tutorial é muito bom, me ajudou muito!!!!
Obrigado!!!!

Saulo disse...

Valeu, Glauber.

Estamos aqui lendo para usar no 6 período.

Abraços,

Saulo Calderon

Weslley Nepomuceno disse...

Show de Bola Glauber, mais uma vez parabéns pelo post, ele foi fundamental para começarmos o nosso projeto do 6º periodo, abração cara...

Felipe Teste disse...

Glauber, se seu webservice retornasse um objeto











Como faria para ler os telefones?

Nelson Glauber de Vasconcelos Leal disse...

Oi Felipe,

Se você observar, o webservice acima retorna um objeto...

4br4ç05,
nglauber

Carlos disse...

o que há de errado nesse código?

SoapObject soap = new SoapObject(
"http://localhost:8080/axis2/services/webservice", "getnome");

soap.addProperty("nome", "carlos");

SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.setOutputSoapObject(soap);
String url = "http://localhost:8080/axis2/services/webservice?wsdl";

HttpTransportSE httpTransport = new HttpTransportSE(url);

try { httpTransport.call("aqui", envelope);
Object msg = envelope.getResponse();
}
catch (Exception e) {
e.printStackTrace(); display.setText("erro");
}

Nelson Glauber de Vasconcelos Leal disse...

Oi Carlos,

Essa linha:

SoapObject soap = new SoapObject(
"http://localhost:8080/axis2/services/webservice", "getnome");

Deve conter o namespace do seu webservice e não o endereço dele. Olha no WSDL pra saber o que passar nesse parâmetro.

4br4ç05,
nglauber

Unknown disse...

Como faz para gravar dados num banco de dados utiilizando web service?Poderia ser o MySql, obrigado

Nelson Glauber disse...

Oi unknown,

Eu fiz esse tutorial aqui em 2010 (http://www.nglauber.com.br/2010/06/acessando-banco-de-dados-mysql-com-jdbc.html) mas creio que ainda funcione.

4br4ç05,
nglauber

Unknown disse...

Nelson, agradeço o retorno. Preciso para Android acessando o MySql via web service. Como ficaria esse tutorial com web service e MySQL para Android?

Nelson Glauber disse...

Oi Frederico,

Você está tentando fazer 3 coisas ao mesmo tempo. O que não é ruim, mas pode ser complicado. Trabalho com Android que é bem vasto. PHP possui livros de 1000 páginas ou mais e MySQL é um outro assunto.

Recomendo você a ler um bom livro ou tutorial sobre PHP com MySQL. Meu intuito com esse post foi mostrar como acessá-los no Android. E meu exemplo de servidor foi com Java e não PHP.

4br4ç05,
nglauber