Aplicações multiplataforma, HTML5 e Windows Phone 7.5

Você sabe HTML, Javascript e CSS? Aprendeu HTML5 recentemente? Então, já sabe fazer aplicações móveis multiplataforma!

Por Juan Manuel Servera - Tradução CRV


Publicado em: 03/11/11
Valorize este artigo:
Uma das maneiras mais versáteis que temos para criar nossa primeira aplicação para múltiplos dispositivos (IPhone, Android, WP7, etc.) é utilizar HTML + Javascript e adaptá-las um pouco para cada um dos dispositivos sobre os que queremos que funcione.

Como costuma acontecer, há umas quantas formas de criar aplicações HTML5 para móveis:

  1. Criando uma aplicação HTML específica para telas pequenas, podemos usar css condicionais para adaptar melhor o conteúdo. Por serem páginas com conexão não poderemos usá-as quando não disponhamos de conectividade no dispositivo.
  2. Para solucionar o primeiro ponto podemos utilizar o manifest.cache para armazenar a aplicação localmente. Desta maneira poderemos utilizar a aplicação web em modo desconectado, mas não funcionará em todos os dispositivos e temos um limite de memória de 5 MB.
  3. A terceira opção, que ademais pode aproveitar características das outras duas, é usar um controle nativo para conter o HTML e distribuir a aplicação e todo o seu conteúdo como aplicação nativa a partir do mercado de cada uma das plataformas.

As duas primeiras têm a (duvidosa) vantagem de poder esquecer das normativas que exigem os fabricantes em suas lojas online, mas tal aplicação não poderá acessar todos os elementos do dispositivo, mas só os que nos permita o navegador de cada um. Há muitos standards de HTML5 que ainda estão em projeto e portanto cada fabricante decide se o implementa ou não.

Com a terceira opção temos a grande vantagem de poder ir mais além das limitações do navegador e nos comunicar com as API do dispositivo de uma forma mais direta, porém mantendo a vantagem de utilizar HTML5 e javascript para definir tanto o aspecto quanto o comportamento da aplicação.

embeddedIE9

Vamos nos centrar nesta última opção e desenvolveremos um exemplo sobre a plataforma Windows Phone 7. Para as outras plataformas de desenvolvimento só mudará no container, a aplicação HTML será sempre igual.

Tutorial: A aplicação HTML5

Antes de começar, quero informar que todo o código que vamos tratar neste artigo está disponível através de Codeplex.

wp7bounceball320

Mais adiante veremos como nossa aplicação Silverlight se comunicará com a aplicação HTML. Por agora vejamos o que vai fazer nossa aplicação HTML5. Vamos criar um canvas onde desenhar uma bola que se mova segundo a inclinação do dispositivo. Para isso necessitaremos usar o evento devicemotion definido em um draft de HTML5 e utilizaremos esses valores para dar aceleração à bola.

<!DOCTYPE html>
<html>
<head>
<title>Bouncing Ball Animation</title>
<link href="main.css" rel="stylesheet" />
<script type="text/javascript" src="WP7Bridge.js" ></script>
<script type="text/javascript">
   //holds the drawing context of the canvas element
   var context;
   //loads the bounce sound for the ball
   var sound;
   
   //size of canvas
   var width = 800;
   var height = 800;
   
   //position of the ball
   var x = 400;
   var y = 40;
   
   //speed of the ball, initially 0
   var dx = 0;
   var dy = 0;
   
   //ball radius
   var ballRadius = 35;
   
   function init() {
      context = document.getElementById("playCanvas").getContext("2d");
   
      sound = new Audio("107785__hans__tink.mp3");
      sound.load();
      playSound(0); //this avoids lag the first time
   
      //keep calling draw function after every 20 milliseconds
      setInterval(draw, 20);
   }
   
   //store old values to know if there's a real change
   var oldx, oldy;
   
   function draw() {
      //change the position by delta
      x += dx;
      y += dy;
   
      //have some small friction
      dx *= 0.95;
      dy *= 0.95;
   
      var xcol = false;
      var ycol = false;
   
      //collision detection and bounce
      if (x + ballRadius > width) {
         dx = -dx/2.0;
         x = width - ballRadius;
         xcol = true;
      } else if (x < ballRadius) {
         dx = -dx/2.0;
         x = ballRadius;
         xcol = true;
      }
      if (y + ballRadius > height) {
         dy = -dy / 2.0;
         y = height - ballRadius;
         ycol = true;
      } else if (y < ballRadius) {
         dy = -dy / 2.0;
         y = ballRadius;
         ycol = true;
      }
   
      if (xcol && x != oldx && Math.abs(dx) > 1) {
         playSound(Math.min(1, 0.75 + (Math.abs(dx) * 0.05)));
      }
      else if (ycol && y != oldy && Math.abs(dy) > 1) {
         playSound(Math.min(1, 0.75 + (Math.abs(dy) * 0.05)));
      }
   
      //store old values for comparing and perform click
      oldx = x;
      oldy = y;
   
      //clears everything
      clear();
      //draws external rectangle
      rectangle(0, 0, width, height);
      //draws the ball at its current position
      circle(x, y, ballRadius);
   }
   
   //draws the circle with center location at x,y
   function circle(x, y, radius) {
      context.fillStyle = "#444444";
      context.beginPath();
      context.arc(x, y, radius, 0, 2 * Math.PI, true);
      context.closePath();
      context.fill();
   }
   
   //draws a rectangle with width(w) & height(h) with top left corner at (x,y)
   function rectangle(x, y, w, h) {
      context.fillStyle = "#000000";
      context.lineWidth = "4";
      context.strokeRect(x, y, w, h);
   }
   
   //clears the whole canvas
   function clear() {
      context.clearRect(0, 0, width, height);
   }
   
   function motionChanged(event) {
    //change delta increment by gravity
    dx += event.accelerationIncludingGravity.x/10.0;
    dy += -event.accelerationIncludingGravity.y/10.0;
   }
   
   function playSound(volume) {
    sound.volume = volume;
    sound.play();
   }
   
   window.addEventListener("load", init, true);
   window.addEventListener("devicemotion", motionChanged, true);
</script>
</head>
<body>
<header>Hello HTML5</header>
<div id="wrapper">
   <canvas id="playCanvas" width="800" height="800" >
   </canvas>
</div>
</body>
</html>

Até agora escrevemos uma aplicação HTML simples e com só uma linha "suspeita", a que aponta para um script chamado WP7Bridge.js. É o script que usaremos para fazer de ponte entre o motor javascript e as API do telefone.

Dentro de algum tempo a partir de HTML5 teremos acesso a grande de parte das apis e sensores que trazem os novos dispositivos (cámara, brújula y giroscopio, etc…), mas há que ter em conta que muitas destas API ainda estão em fase de projeto , alguns navegadores não a implementam e outros têm que ser atualizados muito frequentemente porque o API vai mudando, deixando nossas aplicações sem essa funcionalidade como aconteceu com o API de WebSocket não faz muito tempo .

No caso de Windows Phone 7 temos acesso à API de geolocalização a partir de HTML5, mas ainda não foi implementado o acesso ao acelerômetro. Para que posamos nos comunicar com o acelerômetro do dispositivo vamos usar um método que executará o evento devicemotion como se fosse um evento nativo, utilizando o método window.dispatchEvent:

// js receiver for the accelerometer
// from the phone, fires the devicemotion event
// as defined in http://www.w3.org/TR/orientation-event/
function wp7ExtensionsaccelerometerChanged(x, y, z, intervalms) {
   //here we create a fake deviceorientation event!
   var event = document.createEvent("Event");
   event.initEvent("devicemotion", true, true);
   event.acceleration = null;// new Acceleration();
   event.accelerationIncludingGravity = new Acceleration();
   event.accelerationIncludingGravity.x = parseFloat(x);
   event.accelerationIncludingGravity.y = parseFloat(y);
   event.accelerationIncludingGravity.z = parseFloat(z);
   event.rotationRate = null;// new RotationRate();
   event.interval = parseInt(intervalms);
   window.dispatchEvent(event);
};

Armazenaremos este método no arquivo WP7Bridge.js e partir da parte nativa da aplicação do dispositivo chamaremos este método cada vez que se produza uma mudança no acelerômetro. Desta maneira poderemos criar qualquer ponte entre as capacidades do dispositivo e as aplicações HTML5. Para o caso do WP7 vamos criar uma aplicação Silverlight, que tem acesso aos sensores do dispositivo, e que conterá um control WebBrowser onde alojaremos nossa aplicação.

Tutorial: A aplicação Silverlight

Nota: Para poder realizar este tutorial é necessário ter instaladas as últimas ferramentas de Windows Phone 7. No momento de escrever este artigo estamos na Beta 2 da versão 7.1, comprovem se há uma versão mais nova:
http://www.microsoft.com/download/en/details.aspx?id=26648

Como já comentei com vocês, nossa aplicação HTML5 terá que viver dentro de uma aplicação do dispositivo, desta maneira poderemos empacotá-la e distribuí-la como qualquer outra aplicação. Para tanto criaremos uma solução de tipo Windows Phone com as ferramentas e inseriremos um elemento WebBrowser no Grid principal.

<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
   <phone:WebBrowser x:Name="webBrowser"
            Navigated="webBrowser_Navigated"
            IsScriptEnabled="True"
            IsGeolocationEnabled="False"
            Source="html/default.htm"
            />
</Grid>

Vocês vão ver que o control tem uma série de propriedades:

  • IsScriptEnabled: necessitaremos dela ativada para poder executar javascript na página.
  • IsGeolocationEnabled: nos habilitará o GPS e poderemos usar as funções Javascript de geolocalização (navigator.geolocation.getCurrentPosition)
  • Source: aponta para a página HTML que queremos abrir.

No código da página XAML que contém o WebBrowser criaremos nossa ponte que nos permitirá realizar chamadas ao código Javascript. Criaremos uma instancia do acelerômetro e em cada evento chamaremos um método do componente browser que nos permitirá chamar qualquer script definido na página WebBrowser.InvokeScript.

public class Html5Bridge:IDisposable
{
   Accelerometer _accelerometer;
   WebBrowser _browser;
   public Html5Bridge(WebBrowser browser, bool enableAccelerometer)
   {
      _browser = browser;
      browser.ScriptNotify += browser_ScriptNotify;
      if (enableAccelerometer)
      {
         _accelerometer = new Accelerometer();
         _accelerometer.CurrentValueChanged += _accelerometer_CurrentValueChanged;
         _accelerometer.Start();
      }
   }
   
   void _accelerometer_CurrentValueChanged(object sender, SensorReadingEventArgs e)
   {
      Vector3 v = e.SensorReading.Acceleration;
   
      Deployment.Current.Dispatcher.BeginInvoke(() =>
      {
         _browser.InvokeScript("wp7ExtensionsaccelerometerChanged",
         (v.X * 9.81).ToString(System.Globalization.CultureInfo.InvariantCulture),
         (v.Y * 9.81).ToString(System.Globalization.CultureInfo.InvariantCulture),
         (v.Z * 9.81).ToString(System.Globalization.CultureInfo.InvariantCulture),
         _accelerometer.TimeBetweenUpdates.Milliseconds.ToString(System.Globalization.CultureInfo.InvariantCulture)
         );
      });
   }
...

Para finalizar, no WP7.5 teremos que usar algum truque mais para poder carregar o conteúdo HTML local no WebBrowser, pois não temos permissão para acessar diretamente os arquivos que inclui nosso arquivo XAP. Para solucioná-lo basta copiar esses arquivos no sistema de arquivos local justo no momento de arranque da aplicação:

private void Application_Launching(object sender, LaunchingEventArgs e)
{
   string[] files = new string[] {
      "107785__hans__tink.mp3",
      "default.htm",
      "WP7Bridge.js",
      "main.css" };
   using (var store = IsolatedStorageFile.GetUserStoreForApplication())
   {
      store.CreateDirectory("html");
      foreach (string file in files)
      {
         var info = Application.GetResourceStream(new Uri("html/" + file, UriKind.Relative));
         if (info != null)
         {
            using (var writeStream = new IsolatedStorageFileStream("html" + file, FileMode.Create, store))
            {
               byte[] bytes;
               using (var binaryReader = new BinaryReader(info.Stream))
               {
                  bytes = binaryReader.ReadBytes((int)info.Stream.Length);
               }
               using (var writer = new BinaryWriter(writeStream))
               {
                  writer.Write(bytes);
               }
            }
         }
      }
   }
}

Conclusões

Escrevendo um mínimo de código para a plataforma, o qual será comum ao resto de nossas aplicações HTML5, conseguimos que nossa aplicação HTML5 funcione em Windows Phone 7.5. Para os demais dispositivos será muito parecido. Assim costumam fazê-lo plataformas como phonegap para permitir executar o mesmo código em todos os dispositivos.





Comentários do artigo
Foi enviado 1 comentário ao artigo
1 comentário não revisado
0 comentários revisados

Usuários :    login / registro

Manuais relacionados
Categorias relacionadas
O autor
Juan Manuel Servera - Tradução CRV
Technical Manager en el Microsoft Innovation Center | Tourism Technologies
http://jmservera.wordpress.com

Home | Sobre nós | Copyright | Anuncie | Entrar em contato