Nesta lição, estudaremos a Conectividade.
Baixe os arquivos correspondentes a esta aula. A pasta completa está em:
O trabalho "Criação de aplicações Móveis com PhoneGap e jQuery Mobile" de Cleuton Sampaio de Melo Jr está licenciado com uma Licença Creative Commons - Atribuição-CompartilhaIgual 4.0 Internacional. Isso inclui: Textos, páginas, gráficos e código-fonte.
Conectividade
O grande lance das aplicações móveis é a conectividade. Aplicações “standalone”, que não se comunicam com nenhum Serviço, são raras e, geralmente, de pouca utilidade em plataforma móvel. Temos que lembrar que o usuário é movel e está com uma plataforma computacional de grande poder em seu bolso.No início da Internet móvel (WAP), a grande novidade era acessar seu e-mail ou então navegar em websites WAP. Hoje em dia, podemos fazer muito mais do que isso.
Arquitetura típica de conectividade
Basicamente, temos dois tipos de comunicação: Consumo de
Serviços e “Push”. O Consumo de serviços é quando o
dispositivo envia um Request a um Servidor na Web, o que, geralmente,
é feito utilizando-se HTTP, e recebe uma resposta. O Web Service
pode ser SOAP ou HTTP puro, e o formato de dados pode ser JSON ou
XML.
Podemos consumir serviços utilizando HTTP puro, e o jQuery nos fornece vários métodos para isto:
Consumo usando HTTP
Podemos consumir serviços utilizando HTTP puro, e o jQuery nos fornece vários métodos para isto:
Get de dados a
partir de um servidor:
$.get(“<url>”, <callback>)
$("button").click(function(){
$.get("demo_test.asp",function(data,status){
alert("Data: " + data + "\nStatus: " +
status);
});
});
Post de dados
para um servidor:
$.post(URL,data,callback);
$("button").click(function(){
$.post("demo_test_post.asp",
{
name:"Donald Duck",
city:"Duckburg"
},
function(data,status){
alert("Data: " + data + "\nStatus: " +
status);
});
});
Get de um
objeto JSON a partir de um servidor:
$.getJSON( url [, data ] [, success ] )
$.getJSON( "ajax/test.json", function( data ) {
var items = [];
$.each( data, function( key, val ) {
items.push( "<li id='" + key + "'>" +
val + "</li>" );
});
$( "<ul/>", {
"class": "my-new-list",
html: items.join( "" )
}).appendTo( "body" );
});
E temos também o
método “Ajax”, que é mais completo:
$.ajax({
type: "POST",
url: wsUrl,
contentType: "text/xml",
dataType: "xml",
data: soapRequest,
success: processSuccess,
error: processError
});
Sempre temos que
passar “callbacks” para os eventos, além de testarmos o status
da resposta:
200 OK
O Request foi bem
sucedido. O conteúdo da resposta estará de acordo com o campo
“Content-type”.
301 Moved Permanently
302 Found
303 See Other
É necessário
fazer um “redirect” para outra URL, informada no HEADER da
resposta.
304 Not Modified
O Recurso que você
está tentando obter não sofreu modificações, logo, o que está em
seu “cache” é válido. Isso depende do conteúdo do ETag e da
data de modificação, e você pode controlar isso com os tags no
Request: “if-none-match” e “if-modified-since”.
400 Bad Request
Seu request não
foi entendido pelo Servidor. Verifique o formato e os HEADERS.
401 Unauthorized
O acesso ao
Recurso exige autenticação. A resposta deve incluir um HEADER
“WWW-Authenticate” que contém um “challenge” a ser devolvido
no próximo request. O Cliente pode repetir o request incluindo o
HEADER: “Authorization”. Se o Request original já incluiu o
HEADER “Authorization”, então é uma indicação que o usuário
não tem direito de acesso ao Recurso.
403 Forbidden
O Servidor
entendeu o request, porém não vai enviar o recurso. Neste caso, não
adianta incluir o HEADER “Authorization” e o Request não deve
ser repetido.
404 Not Found
O Recurso não foi
encontrado. Pode ser um problema de URI, indicando que o nome ou a
identificação do Recurso estejam inválidos.
405 Method Not Allowed
O Método HTTP que
você está enviando em seu Request não é aceito pelo Servidor para
este Recurso. Por exemplo, você pode estar tentando obter um recurso
com GET, mas ele só está disponível via POST.
406 Not Acceptable
Quando criamos um
Request, podemos especificar quais tipos de resposta aceitaremos, por
exemplo: XML, JSON, HTML ou TEXT. Se o Servidor concluir que não
pode enviar o Recurso naquele formato, ele retorna um erro 406.
5XX Erro de servidor
Este tipo de erro
é retornado devido a um problema no Servidor. Pode ser que tenha
dado uma exception, ou mesmo que o Serviço esteja fora do ar.
Exercício 1
Vamos fazer um
exercício breve (guiado) para consumir um serviço via HTTP. Vamos
verificar de onde é nosso Endereço IP.
Para começar:
- cordova create geoip com.exemplo.geoip geoip
- cordova platform add android
Depois, crie uma
página HTML “index.html” de acordo com as orientações da
Sessão 3, página 5. Lembre-se de copiar os arquivos do “jQuery”
e do “jQuery Mobile” para dentro da pasta “js” (estão dentro
da sessão 3 em “jquery-mobile”). E a CSS do jQuery Mobile para a
pasta “css”.
Importe os
projetos “geoip” e “geoip-CordovaLib” para sua Workspace.
(“Inport / Android / Existing Android Code...”). Se der erro no
projeto “geoip”, abra o “Build Path” e adicione o projeto
“geoip-CordovaLib”.
Lembre-se de
excluir os “Resource filters” para que os arquivos www apareçam.
O que você vai
fazer? Vai acessar uma API REST que retorna um JSON. Pode usar o
método $.getJSON, do jQuery:
console.log("************
Fazendo o request:");
$.getJSON(
"http://freegeoip.net/json", function( data ) {
console.log("************
Dados recebidos: " ]
+
JSON.stringify(data));
$("#saida").text(JSON.stringify(data));
});
Eis o resultado
esperado:
O serviço
“freegeoip.net” retorna as informações geográficas de um
endereço IP, e pode fazê-lo em formato JSON ou XML. Eis a url:
http://freegeoip/<formato>[/<endereço
ip>]
O código de
acesso ao Webservice deve ser incluído no evento “ondeviceready”,
do Cordova.
Trabalhando o JSON
As respostas JSON
são fáceis de trabalhar em Javascript. Elas já são Objetos e
podemos usar suas propriedades e métodos. O objeto recebido foi mais
ou menos esse:
{
"ip":"189.9.136.5",
"country_code":"BR",
"country_name":"Brazil",
"region_code":"",
"region_name":"",
"city":"",
"zipcode":"",
"latitude":-10,
"longitude":-55,
"metro_code":"",
"area_code":""
}
Logo, poderíamos
ter trabalhado os valores individualmente:
console.log("@@@
País: " + data.country_name);
E podemos usar o
método JSON.stringify() para transformar um Objeto em String.
Trabalhando com XML
Trabalhar com XML
em plataforma móvel não é fácil. Nem todos os recursos estão
disponíveis. Se você tiver oportunidade, evite trabalhar com XML a
qualquer custo!
Isto posto, vamos
ver com trabalhar com XML no ambiente móvel com jQuery. O serviço
“freegeoip” também permite obter os dados em XML. Por exemplo:
Podemos trabalhar
isso de maneira simples:
$.get("http://freegeoip.net/xml",
function( data ) {
console.log("$$$$
" + $('CountryName',data).text());
}
);
Usamos o próprio
seletor do jQuery para pegar o elemento “CountryName” de dentro
da resposta XML, que estava na variável “data”. Usamos o método
“text()” para obter o conteúdo do Tag.
Poderíamos ter
navegado em todos os tags que estão dentro do tag inicial
(<Response>) dessa forma:
$.get("http://freegeoip.net/xml",
function( data ) {
$("Response",
data).each(function() {
console.log("@@@@@@@@@@@@@@@@@@");
console.log("Ip:
" + $(this).find("Ip").text());
console.log("CountryCode:
" + $(this).find("CountryCode").text());
console.log("CountryName:
" + $(this).find("CountryName").text());
});
Usamos o método
“each()” dentro do tag “Response”, para navegar em todos os
tags encontrados. Depois, para cada tag encontrado, mostramos o seu
conteúdo textual.
O “find()” tem
que ser executado no tag superior.
SOAP
SOAP é um protocolo de troca de informações, baseado na
invocação remota de operações (métodos). Ele necessita de um
formato específico de mensagem, descrito em um arquivo WSDL.
Antes de mais nada, instale o programa “soapui”:
Por que você vai precisar do SOAPUI? Porque você terá que
montar o SOAP Envelope na mão!
Vamos criar um Projeto SOAP no SOAP UI e usar o serviço
“Calculator”. Eis o endereço do WSDL:
Vamos invocar a soma (add):
Eis a Resposta:
<soap:Body>
<n:addResponse xmlns:n="http://www.parasoft.com/wsdl/calculator/">
<n:Result xsi:type="xsd:float">700.0</n:Result>
</n:addResponse>
</soap:Body>
</soap:Envelope>
Como fazer isso em uma app?
Temos que montar o SOAP Envelope, enviar usando POST e depois
analisar a resposta.
Montando o SOAP Envelope
<soapenv:Header/>
<soapenv:Body>
<cal:add>
<cal:x>500</cal:x>
<cal:y>200</cal:y>
</cal:add>
</soapenv:Body>
</soapenv:Envelope>
Temos que colocar isso dentro de um String:
+ " xmlns:cal='http://www.parasoft.com/wsdl/calculator/'>"
+ "<soapenv:Header/>"
+ "<soapenv:Body>"
+ "<cal:add>"
+ "<cal:x>"
+ 500
+ "</cal:x>"
+ "<cal:y>"
+ 200
+ "</cal:y>"
+ "</cal:add>"
+ "</soapenv:Body>"
+ "</soapenv:Envelope>";
O Header SOAPAction
Note que o POST
request tem um header SOAPAction, indicando qual é a operação
desejada.
Algumas
implementações de Web Services, especialmente usando SOAP 1.1,
exigem a presença deste HEADER no POST.
Juntando tudo
Eis a
implementação:
receivedEvent: function(id) {
var soapEnv = "<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'"
+ " xmlns:cal='http://www.parasoft.com/wsdl/calculator/'>"
+ "<soapenv:Header/>"
+ "<soapenv:Body>"
+ "<cal:add>"
+ "<cal:x>"
+ 500
+ "</cal:x>"
+ "<cal:y>"
+ 200
+ "</cal:y>"
+ "</cal:add>"
+ "</soapenv:Body>"
+ "</soapenv:Envelope>";
$.ajax({
type: "POST",
url: "http://ws1.parasoft.com/glue/calculator",
headers: { 'SOAPAction': 'add' },
contentType: "text/xml;charset=UTF-8",
dataType: "xml",
data: soapEnv,
success: function(data, status, req) {
console.log("****** OK: " + status);
$("#saida").text($("Result",data).text());
},
error: function(request, status, error) {
console.log("***** ERRO: " + status + " : " + error);
}
});
}
Notificações
Notificações “Push”, para Android e iOS, são providas por seus respectivos serviços de notificações:
Google Cloud Messaging
Apple Push Notification Service
Windows Phone Push Notification Service
A conectividade “Push” funciona sem necessidade do usuário
acionar uma aplicação. Em seu dispositivo, um Serviço abre uma
conexão com o Serviço de Notificações na Nuvem, e fica
aguardando. Quando chega uma notificação, ela vem com o “id” da
aplicação, logo, o Serviço de background consegue enviar a
mensagem para a aplicação, mesmo que ela não esteja sendo
executada.
Ao receber notificações, o dispositivo exibe uma lista:
Ao clicar em uma notificação, a aplicação correspondente será
aberta, no “callback” de tratamento de notificações. Ela poderá
fazer várias coisas, por exemplo abrir uma janela com a mensagem
nova.
Badge number
No iOS é possível adicionar um “Badge number” ao ícone da
aplicação, geralmente mostrando quantos novos itens estão
disponíveis:
Nos dispositivos Android isso não é possível, pois a API não
permite alterar o ícone de um aplicativo.
Porém, se for absolutamente necessário exibir esse tipo de informação, você pode criar um Widget para o usuário Android.
Em aparelhos
Samsung, a interface TouchWiz permite criar Badge Numbers. A
desvantagem é que só funciona com aparelhos Samsung.
O processo de notificação
Existe todo um processo para poder enviar notificações de “push”
para os aparelhos. Para começar, é de bom tom perguntar ao usuário
se o aplicativo pode lhe enviar notificações de “push”. Depois,
é necessário registrar seu aplicativo nos serviços de “push”
que deseja utilizar: GCM, APNs ou WPPNS .
Em segundo lugar, você terá que criar uma aplicação que
enviará as mensagens ao Servidor de Notificações desejado. Essa
aplicação se registrará no Servidor de Notificação (usando as
credenciais que você registrou), e enviará as mensagens para os
usuários que se registraram com a aplicação. Note que ele não
enviará as mensagens diretamente aos aparelhos, mas para o Servidor
do serviço de notificações apropriado.
Finalmente, sua aplicação deverá estar preparada para receber
notificações de “push”, fornecendo um “callback” a ser
executado quando as mesmas chegarem.
As mensagens de notificações não possuem garantia de entrega.
Sequência de passos para notificações
Toda aplicação que usa notificações
de “push” deve ter pelo menos 4 partes:
- Aplicação móvel;
- Aplicação servidora (Servidor de Aplicação);
- Banco de dados com o registro dos usuários;
- Servidor de Notificação (Feito pela Google, Apple ou Microsoft).
A sequência seria mais ou menos esta:
- Usuário instala a aplicação;
- Aplicação se registra com o Servidor de Notificações (do
provedor escolhido: GCM, APNs ou WPPNS);
- Aplicação envia ao Servidor de Aplicação a sua
identificação, que é armazenada no banco de dados;
- Em um dado momento, o Servidor de Aplicação decide enviar
notificação para um dos Clientes. Ele obtém a identificação do
Banco de dados de registro;
- O Servidor de Aplicação contacta o Servidor de Notificações
e solicita o envio de notificação para um ou mais registros de
usuário;
- O Servidor de Notificação contata o dispositivo do usuário
e envia a notificação;
- Um “callback” no dispositivo móvel registra a
notificação e exibe na lista de notificações;
- Quando o usuário toca em uma notificação, a aplicação apropriada é acionada, e um “callback” é executado.
Dependendo do requisito, a aplicação pode fazer diversas coisas
ao receber uma notificação:
- Apagar o “Badge number”, se for o caso;
- Enviar uma confirmação ao Servidor de Aplicação, para que este evite notificá-la novamente;
Notificações para aparelhos Android
Para enviar notificações para aparelhos Android, é necessário
criar um projeto e se registrar no serviço Google Cloud Messaging.
Primeiro passo: Criar um projeto de uso de API Google
Acesse a Google Developers Console e crie um novo projeto:
Anote os campos “project ID” e “project Number”.
Na barra à esquerda, selecione “APIs & auth”.
Na lista de APIs, ligue a opção correspondente a “Google Cloud
Messaging for Android”:
Segundo passo: Criar uma chave de API (API Key)
- No painel esquerdo, selecione: “APIs & auth” e
“Credentials”;
- Dentro de “Public API access”, selecione “Create new
key”;
- No diálogo “Create a new key”, selecione: “Server
key”;
- No diálogo seguinte, informe o Endereço IP onde seu
Servidor de Aplicação vai rodar. Para testar, deixe como:
0.0.0.0/0. ATENÇÃO: NUNCA COLOQUE EM PRODUÇÃO ASSIM!
- Selecione: “Create”;
- Na página a seguir, copie a “API key”. Você necessitará dela para autenticar seu Servidor de Aplicação com o Google Cloud Messaging.
Terceiro passo: Criar uma aplicação preparada para GCM
Este exemplo é baseado neste TUTORIAL.
- Crie uma aplicação PhoneGap (pode ser com os utilitários
do Cordova);
- Adicione o “PushPlugin”:
- phonegap local plugin add
https://github.com/phonegap-build/PushPlugin;
- Copie o arquivo “PushNotification.js”, que fica na pasta
do projeto, dentro de “/plugins”, para a pasta raiz do projeto
(que vai virar “assets/www”);
- Insira uma referência para o “PushNotification.js”
dentro da sua página “index.html”:
- phonegap local plugin add
https://github.com/phonegap-build/PushPlugin;
- <script type="text/javascript"
src="PushNotification.js"></script>
- Registre a aplicação com o Google Cloud Messaging;
- Codifique o “callback” de sucesso no regisro da app;
- Codifique o “callback” de erro no registro da app;
- Codifique o “callback” a ser invocado quando chegarem
mensagens para a app;
Importe o projeto “PushNotificationApp” para o eclipse.
Referência para o plugin (arquivo “index.html”):
<script
type="text/javascript" src="cordova.js"></script>
<script
type="text/javascript" src="js/index.js"></script>
<script
type="text/javascript" src="PushNotification.js"></script>
<script
type="text/javascript">
app.initialize();
</script>
Código que registra a app no GCM (arquivo “index.js”):
var pushNotification = window.plugins.pushNotification;
pushNotification.register(
app.successHandler,
app.errorHandler,
{"senderID":"954182423629",
"ecb":"app.onNotificationGCM"});
Você não precisa registrar sua app a todo momento no GCM. Pode
fazer isso e armazenar em um Banco local, testando sempre se a tabela
está vazia.
Os argumentos são:
- app.successHandler : “callback” de sucesso no registro
com o GCM;
- app.errorHandler : “callback” de erro no registro com o
GCM;
- {"senderID":"954182423629","ecb":"app.onNotificationGCM"}:
O “SenderID” é o seu “ProjectID”, recebido quando você
criou o projeto na Google Developers Console, e o “ecb” é o
“callback” que será invocado quando chegar uma mensagem;
Processamento de mensagens
O código que processa mensagens é bem simples:
switch( e.event )
{
case 'registered':
if ( e.regid.length > 0 )
{
console.log("Regid " + e.regid);
alert('registration id = '+e.regid);
}
break;
case 'message':
// this is the actual push notification. its format depends on the
//data model from the push server
alert('message = '+e.message+' msgcnt = '+e.msgcnt);
break;
case 'error':
alert('GCM error = '+e.msg);
break;
default:
alert('An unknown GCM event has occurred');
break;
}
}
Vários eventos podem ocorrer quando chega uma mensagem:
- “registered”: Quando a aplicação se registrou com o
GCM;
- “message”: Quando uma mensagem foi recebida;
- “error”: Quando ocorreu um erro.
O que vem dentro da mensagem e o que a sua aplicação vai fazer
com ela, depende muito da sua funcionalidade. O normal é abrir uma
tela com os dados da mensagem nova.
O Servidor de Aplicação
Para este tutorial, usamos um servidor Node.js (arquivo
“notify.js”):
var gcm = require('node-gcm');
var message = new gcm.Message();
//API Server Key
var sender = new gcm.Sender('**** API KEY GCM ****');
var registrationIds = [];
// Value the payload data to send...
message.addData('message',"\u270C Peace, Love \u2764 and PhoneGap \u2706!");
message.addData('title','Push Notification Sample' );
message.addData('msgcnt','3'); // Shows up in the notification in the status bar
message.addData('soundname','beep.wav'); //Sound to play upon notification receipt - put in the www folder in app
message.collapseKey = 'demo';
message.delayWhileIdle = true; //Default is false
message.timeToLive = 3000;// Duration in seconds to hold in GCM and retry before timing out. Default 4 weeks (2,419,200 seconds) if not specified.
// At least one reg id required
registrationIds.push("APA91bG_WLY0gUm872ez4tOD3Bc7tIiIJr6DoQHh0YT2LKOZIgCDxqOA3hnrDrGBN4mI53PWCfuCuWfolAvZ2AfZP5hTBbRGI5X6dD9X8mVatP8C0d40L_WnW_y-N_W2sorNfN7XlVAVn-AOco4W4DztoVplNbYuI7vj5z6DKVxurtn409VEZZc");
/**
* Parameters: message-literal, registrationIds-array, No. of retries, callback-function
*/
sender.send(message, registrationIds, 4, function (err, result) {
if(err) {
console.log('Erro: ' + err);
}
if (result) {
console.log('Result: ' + JSON.stringify(result));
}
else {
console.log('Result nulo');
}
});
O ideal é termos um Webservice que a aplicação invoque para
informar seu “Registration Id” (obtido quando ela se registra no
GCM). Então, armazenamos esse Registration Id em um banco de dados.
É importante que você tente seguir exatamente todos os passos e teste a aplicação!
Eis as duas telas da aplicação:
Abra o site do Webservice e veja como ele funciona.
WSDL: http://www.webservicex.net/stockquote.asmx?WSDL
Site: http://www.webservicex.com/ws/WSDetails.aspx?CATID=12&WSID=56
Usando o “soapui”, fiz um request para a operação “GetWeather”. Eis o request e o response:
Request:
POST http://www.webservicex.com/globalweather.asmx HTTP/1.1
Vamos criar outra app
Vamos criar uma app que permita ao usuário selecionar uma cidade e mostre o clima atual. Para isto, vamos usar o Webservice SOAP/XML “Global Weather”, para listar o clima da cidade desejada. (resposta em “exercicio2.zip”).É importante que você tente seguir exatamente todos os passos e teste a aplicação!
Eis as duas telas da aplicação:
Abra o site do Webservice e veja como ele funciona.
WSDL: http://www.webservicex.net/stockquote.asmx?WSDL
Site: http://www.webservicex.com/ws/WSDetails.aspx?CATID=12&WSID=56
Usando o “soapui”, fiz um request para a operação “GetWeather”. Eis o request e o response:
Request:
POST http://www.webservicex.com/globalweather.asmx HTTP/1.1
Accept-Encoding:
gzip,deflate
Content-Type:
text/xml;charset=UTF-8
SOAPAction:
"http://www.webserviceX.NET/GetWeather"
Content-Length:
406
Host:
www.webservicex.com
Connection:
Keep-Alive
User-Agent:
Apache-HttpClient/4.1.1 (java 1.5)
SOAP Envelope:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://www.webserviceX.NET">
<soapenv:Header/>
<soapenv:Body>
<web:GetWeather>
<!--Optional:-->
<web:CityName>Rio de Janeiro</web:CityName>
<!--Optional:-->
<web:CountryName>Brazil</web:CountryName>
</web:GetWeather>
</soapenv:Body>
</soapenv:Envelope>
Response (SOAP Envelope):
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetWeatherResponse xmlns="http://www.webserviceX.NET">
<GetWeatherResult><![CDATA[<?xml version="1.0" encoding="utf-16"?>
<CurrentWeather>
<Location>Rio De Janeiro Aeroporto , Brazil (SBRJ) 22-54S 043-10W</Location>
<Time>Sep 23, 2014 - 06:00 AM EDT / 2014.09.23 1000 UTC</Time>
<Wind> from the N (350 degrees) at 5 MPH (4 KT):0</Wind>
<Visibility> greater than 7 mile(s):0</Visibility>
<Temperature> 66 F (19 C)</Temperature>
<DewPoint> 62 F (17 C)</DewPoint>
<RelativeHumidity> 88%</RelativeHumidity>
<Pressure> 30.15 in. Hg (1021 hPa)</Pressure>
<Status>Success</Status>
</CurrentWeather>]]></GetWeatherResult>
</GetWeatherResponse>
</soap:Body>
</soap:Envelope>
O elemento <GetWeatherResult> é um CDATA, logo, é apenas
um “string” e não um documento XML, apesar de estar formatado
como tal. Ele será recebido com “<” e “>” ao
invés dos caracteres: “<” e “>”. Veja o exemplo “raw”:
Então, podemos pegar o conteúdo textual do tag “GetWeatherResult” e transformar em XML:
Passo 1: Crie uma aplicação e importe para o eclipse;
Passo 2: Adapte o “index.js” e o “index.html”:
Passo 3: Crie as “pages” do exercício:
HTTP/1.1
200 OK
Cache-Control:
private, max-age=0
Content-Type:
text/xml; charset=utf-8
Server:
Microsoft-IIS/7.0
X-AspNet-Version:
4.0.30319
X-Powered-By:
ASP.NET
Date:
Tue, 23 Sep 2014 10:52:15 GMT
Content-Length:
1023
Connection:
keep-alive
<?xml
version="1.0" encoding="utf-8"?><soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><GetWeatherResponse
xmlns="http://www.webserviceX.NET"><GetWeatherResult><?xml
version="1.0" encoding="utf-16"?>
<CurrentWeather>
<Location>Rio
De Janeiro Aeroporto , Brazil (SBRJ) 22-54S 043-10W</Location>
<Time>Sep
23, 2014 - 06:00 AM EDT / 2014.09.23 1000 UTC</Time>
<Wind>
from the N (350 degrees) at 5 MPH (4 KT):0</Wind>
<Visibility>
greater than 7 mile(s):0</Visibility>
<Temperature>
66 F (19 C)</Temperature>
<DewPoint>
62 F (17 C)</DewPoint>
<RelativeHumidity>
88%</RelativeHumidity>
<Pressure>
30.15 in. Hg (1021 hPa)</Pressure>
<Status>Success</Status>
</CurrentWeather></GetWeatherResult></GetWeatherResponse></soap:Body></soap:Envelope>
HTTP/1.1
200 OK
Cache-Control:
private, max-age=0
Content-Type:
text/xml; charset=utf-8
Server:
Microsoft-IIS/7.0
X-AspNet-Version:
4.0.30319
X-Powered-By:
ASP.NET
Date:
Tue, 23 Sep 2014 10:52:15 GMT
Content-Length:
1023
Connection:
keep-alive
<?xml
version="1.0" encoding="utf-8"?><soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><GetWeatherResponse
xmlns="http://www.webserviceX.NET"><GetWeatherResult><?xml
version="1.0" encoding="utf-16"?>
<CurrentWeather>
<Location>Rio
De Janeiro Aeroporto , Brazil (SBRJ) 22-54S 043-10W</Location>
<Time>Sep
23, 2014 - 06:00 AM EDT / 2014.09.23 1000 UTC</Time>
<Wind>
from the N (350 degrees) at 5 MPH (4 KT):0</Wind>
<Visibility>
greater than 7 mile(s):0</Visibility>
<Temperature>
66 F (19 C)</Temperature>
<DewPoint>
62 F (17 C)</DewPoint>
<RelativeHumidity>
88%</RelativeHumidity>
<Pressure>
30.15 in. Hg (1021 hPa)</Pressure>
<Status>Success</Status>
</CurrentWeather></GetWeatherResult></GetWeatherResponse></soap:Body></soap:Envelope>
Então, podemos pegar o conteúdo textual do tag “GetWeatherResult” e transformar em XML:
- Substituímos os “<” e “>” por “<”
e “>”, respectivamente;
- Convertemos o string resultante em XML;
- Pegamos os elementos dentro de “<Location>”.
Passo 1: Crie uma aplicação e importe para o eclipse;
Passo 2: Adapte o “index.js” e o “index.html”:
Devem ficar
como o exemplo da página 5 da sessão 3. Só que copie os scripts de
“jquery-mobile” para dentro de “assets/www/js” e modifique a
referência dentro de “index.html” para usar as cópias locais.
Página “inicial”, com um form:
<div data-role="page" id="inicial">
<div data-role="header">Clima global</div>
<div role="main" class="ui-content">
<h1>Selecione a cidade</h1>
<form id="formcidade" action="#">
<label for="cidade" class="select">Cidade:</label>
<select name="cidade" id="cidade" required
title="Selecione uma cidade!">
<option value="" selected>[selecione]</option>
<option value="Rio de Janeiro" >Rio de
Janeiro</option>
<option value="Sao Paulo">São Paulo</option>
<option value="Belo Horizonte">Belo
Horizonte</option>
<option value="Brasilia">Brasília</option>
<option value="Porto Alegre">Porto Alegre</option>
<option value="Fortaleza">Fortaleza</option>
</select>
<input type="submit" value="Obter" />
</form>
</div>
<div data-role="footer"></div>
</div>
Teremos validação nesse form, logo,
o script “jquery.validate.min.js” deve ser incluído no arquivo
“index.html”.
Agora, uma página “resultado”
para exibir uma listview:
<div data-role="page" id="resultado">
<div data-role="header"><h1>Resultado</h1></div>
<div role="main" class="ui-content">
<div>
<ul id="saida" data-role="listview">
</ul>
</div>
</div>
<div data-role="footer"><hr/></div>
<a href="#inicial" data-transition="slidefade"
class="ui-btn">Fechar</a>
</div>
Passo 4: Crie, no arquivo “index.js”, os códigos de
validação e submit:
Intercepte o
evento “ready” do documento:
- $(document).ready(function() {…});
A primeira
coisa a fazer no “callback” é validar o form:
- $("#formcidade").validate();
Agora, temos
que interceptar o evento “submit” do form:
- $( "#formcidade" ).submit(function( event ) {
A primeira coisa que faremos dentro do
“submit” é verificar se o form está válido:
- event.preventDefault();
- if($("#formcidade").valid())
{
O
“preventDevault()” é para impedir o comportamento normal de
subissão do formulário, já que vamos tratar tudo nós mesmos.
Até
agora, temos isso:
$(document).ready(function() {
$("#formcidade").validate();
$( "#formcidade" ).submit(function( event ) {
event.preventDefault();
if($("#formcidade").valid()) {
}
);
});
Passo 5: Monte o “SOAPEnvelope” para invocar o serviço:
var
soapEnv =
"<soap:Envelope
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' "
+
" xmlns:xsd='http://www.w3.org/2001/XMLSchema' "
+
" xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>"
+
"<soap:Body>"
+
"<GetWeather xmlns='http://www.webserviceX.NET'>"
+
"<CityName>"
+
$("#cidade").val()
+
"</CityName>"
+
"<CountryName>Brazil</CountryName>"
+
"</GetWeather>"
+
"</soap:Body>"
+
"</soap:Envelope>";
Passso 6: Monte a estrutura do comando $.ajax, para poder obter
os dados do clima:
Passo 7: Mensagem de “aguarde...”
$.ajax({
type:
"POST",
url:
"http://www.webservicex.net/globalweather.asmx",
headers:
{ 'SOAPAction':
'http://www.webserviceX.NET/GetWeather' },
contentType:
"text/xml;charset=UTF-8",
dataType:
"xml",
data:
soapEnv,
beforeSend:
function() {
},
complete:
function() {^
},
success:
function(data, status, req) {
},
error:
function(request, status, error) {
});
- A URL do Webservice é obtida do “soapui”. Temos que acrescentar o HEADER HTTP: “SOAPAction”, conforme indicado no “soapui”;
- Depois, temos que enviar o “soapEnv” que formatamos,
dentro da propriedade “data”;
- A propriedade “beforeSend” é um “callback” que será
invocado imediatamente ANTES do request ser enviado. Podemos usar
para exibir uma mensagem do tipo: “aguarde...”;
- A propriedade “complete” é um “callback” que será
invocado quando o request terminar. Podemos usá-la para fechar a
mensagem “aguarde..”;
- A propriedade “success” é um “callback” que será
invocado quando o request terminar e os dados chegarem. Aqui, temos
que trabalhar o XML e inserí-lo na <UL> da página
“resultado”;
- A propriedade “error” é um “callback” que será
invocado em caso de erro;
Passo 7: Mensagem de “aguarde...”
Podemos usar o Widget “loading”,
do jQuery Mobile, para exibir uma mensagem:
beforeSend:
function() {
$.mobile.loading(
'show', {
text:
'carregando...',
textVisible:
true,
textonly:
true,
theme:
'b',
html:
""
});
} ,
complete:
function() {
$.mobile.loading('hide');
},
Aqui temos que fazer o seguinte:
- Obter o tag “<GetWeatherResponse>”;
- Navegar nos seus tags internos (só tem um);
- Pegar o conteúdo textual;
- Transformar o string em XML;
- Navegar no resultado e montar a listview;
Obter o
tag “<GetWeatherResponse>”
var
response = $(data).find("GetWeatherResponse");
Navegar
nos seus tags internos
$(response).each(function()
{
});
Pegar o
conteúdo textual:
var
respostaString = “”;
$(response).each(function()
{
respostaString +=
$(this).text();
});
Transformar
o String em XML:
respostaString
= respostaString.replace("<", "<");
respostaString
= respostaString.replace(">", ">");
var
respostaXml = $.parseXML(respostaString);
Navegar no resultado e montar a
listview:
var resultHtml = “”;
$('CurrentWeather', respostaXml).each(function() {
resultHtml += "<li>Localização: "
+ $(this).find("Location").text() + "</li>";
// … (outros campos)
});
$("#saida").html(resultHtml);
$("#saida").listview().listview("refresh");
$("#formcidade").get(0).reset();
$.mobile.navigate( "#resultado", {transition: 'pop', role: "dialog" } );
Algumas notas... Para começar, eu não
coloquei todos os campos, logo, você terá que fazer isso. Em
segundo lugar, estamos jogando o resultado (um conjunto de tags
“<li>”) dentro de uma <ul> “listview”. O comando
de “refresh” é estranho, mas é assim mesmo:
$("#saida").listview().listview("refresh");
Como a página
onde está esta <ul> não está carregada, temos que
inicializar a “listview”. Daí a primeira referência ao método
“listview()”. Então, temos que invocar o método “refresh”
da listview, pois acabamos de inserir novos dados, daí a segunda
chamada do método “listview()”.
Limpamos o form com o comando:
$("#formcidade").get(0).reset();
E navegamos (por Javascript) para o
diálogo “resultado”, cuja “listview” nós preenchemos.
Não se esqueça de criar o “callback” de erro!
Nenhum comentário:
Postar um comentário