Desenvolvendo aplicações
    Mobile com HTML, CSS e
           JavaScript
       Aproveitando o conhecimento Web
          no desenvolvimento Mobile



fisl@urubatancom.br      http://www.urubatan.com.br
Palestrante

Rodrigo Urubatan (@urubatan no Twitter) trabalha
 com desenvolvimento de software desde 1997. Já
 desenvolveu sistemas em uma gama de linguagens
 e ambientes, incluindo Delphi, C, C++, PHP, ASP,
 ColdFusion, Assembly, Leather, Ruby e Java.
 Atualmente trabalha com pesquisa e
 desenvolvimento na HP, utilizando principalmente
 Java, Flex e Ruby, e já ministrou cursos e palestras
 em diversos eventos pelo Brasil. Autor do livro Ruby
 On Rails: Desenvolvimento Fácil e Rápido de
 Aplicações Web.

fisl@urubatancom.br           http://www.urubatan.com.br
Primeira idéia




• Symbian e WebOS suportam aplicações escritas em
  HTML+CSS+Javascript nativamente
• Seria legal fazer o mesmo para Android e iOS
• Vou criar um esqueleto de aplicação com WebKit e rodar
  minha app Symbian WRT no Android!




   fisl@urubatancom.br           http://www.urubatan.com.br
Esqueleto de aplicação
              Android
           Portando WRT para Android




fisl@urubatancom.br       http://www.urubatan.com.br
Layout (main.xml)

<?xml version="1.0" encoding="utf-8"?> <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<WebView android:id="@+id/webView"
android:layout_width="fill_parent" android:layout_height="fill_parent" />
</LinearLayout>




    fisl@urubatancom.br                  http://www.urubatan.com.br
Activity

@Override
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  web = (WebView) findViewById(R.id.webView);
  WebSettings settings = web.getSettings();
  settings.setJavaScriptEnabled(true);
  settings.setJavaScriptCanOpenWindowsAutomatically(true);
  settings.setSupportMultipleWindows(true);
  settings.setSupportZoom(false);
  settings.setPluginsEnabled(true);
  web.setVerticalScrollBarEnabled(true);
  web.setHorizontalScrollBarEnabled(false);
  // Our application's main page will be loaded
  web.loadUrl("file:///android_asset/index.html");
}

     fisl@urubatancom.br                   http://www.urubatan.com.br
Port da API WRT

• É necessário expor os objetos da API WRT para a aplicação
  Android
   o device
   o widget
   o menu
• WebView.addJavascriptInterface(objetoJava,
  “nomeNoJavascript”)




   fisl@urubatancom.br           http://www.urubatan.com.br
Isto daria muito trabalho

          Uma das maiores virtudes dos
          programadores é a preguiça.



fisl@urubatancom.br        http://www.urubatan.com.br
Open Source for the Rescue

      Alguem já deve ter feito isto por mim




fisl@urubatancom.br         http://www.urubatan.com.br
Opções
• PhoneGap
   o APIs Javascript para acesso a recursos de dispositivos
     moveis
   o Suporte para iOS, Android, Symbian, Windoes Mobile,
     WebOS, Bada (em desenvolvimento), WindowsPhone 7
     (em desenvolvimento)
   o UI desenvolvida com Frameworks JS+CSS
   o Licensa BSD ou MIT o que for mais conveniente
• Titanium Mobile
   o APIs Javascript para acesso a recursos de dispositivos
     moveis
   o Suporte para iOS e Android
   o API para UI disponivel com L&F nativos
   o Apache + Comercial para modulos adicionais e suporte

   fisl@urubatancom.br            http://www.urubatan.com.br
Opção e Motivos da Escolha - 1

• Titanium Mobile
   o Falta suporte para Symbian
   o API única para todas as plataformas
   o API própria para UI
   o Possibilidade de utilizar quase o mesmo código para
     gerar aplicações Mobile e Desktop
       Nos exemplos apresentados o código é diferente*
       Mesmo assim, a possibilidade de compartilhar código
        é muito interessante
   o Ambiente de desenvolvimento próprio
   o Build service - gera aplicação nativa para android e iOS a
     partir dos fontes enviados (Serviço pago)

   fisl@urubatancom.br             http://www.urubatan.com.br
Opção e Motivos da Escolha - 2

• PhoneGap
   o Eu uso e gosto do Symbian
   o Possui uma API única para todos os dispositivos
       Com algumas excessões de coisas que funcionam e
        uma e não na outra mas isto esta documentado
   o Eu já conheço gosto de diversos frameworks Javascript
   o Existem frameworks Javascript que me permitem ter uma
     UI "nativa" em todas as plataformas
   o Possibilidade de utilizar a IDE ou editor de textos que me
     convier
   o Phonegap Build - serviço que gera apps nativas para
     todas as plataformas suportadas a partir de um código
     único (Serviço pago)
   fisl@urubatancom.br             http://www.urubatan.com.br
Desvantagens

• Em ambos os casos é necessário ter os SDKs para cada
  uma das plataformas instalado na maquina (Exceto se for
  utilizar o serviço de build)
• Em ambos os casos se for necessária para a aplicação uma
  API não disponível no framework, sera necessário
  implementar nativamente para cada uma das plataformas
  desejadas




   fisl@urubatancom.br          http://www.urubatan.com.br
PhoneGap

        Meu framework favorito para esta
                   tarefa



fisl@urubatancom.br        http://www.urubatan.com.br
APIs nativas disponíveis



Acelerometer           Camera        Capture       Compass

Connection             Contacts      Device        Events

File                   Geolocation   Media         Network

Notification           Storage



       fisl@urubatancom.br            http://www.urubatan.com.br
Frameworks disponíveis para UI




•   jQuery Mobile
•   jQTouch
•   Sencha Touch
•   Guarana-UI
•   Nokia Web Templates for High-End Devices
•   Muitos mais pela web ...




     fisl@urubatancom.br          http://www.urubatan.com.br
Pequeno exemplo




• Este é o código de uma API escrita diretamente para Nokia
  WRT portada depois para Android utilizando PhoneGap
• É uma APP gratuita disponível na OviStore




   fisl@urubatancom.br           http://www.urubatan.com.br
Mobile Pomodoro




fisl@urubatancom.br     http://www.urubatan.com.br
index.html
<html>
  <head>
    <title>Mobile Pomodoro</title>
    <link rel="stylesheet" type="text/css" href="css/basic.css"/>
    <script type="text/javascript" src="lib/jquery.min.js"></script>
    <script type="text/javascript" src="lib/jquery.json-2.2.min.js"></script>
    <script type="text/javascript" src="lib/jquery.countdown/jquery.countdown.js"></script>
    <script type="text/javascript" src="lib/pomodoro.js"></script>
    <style type="text/css">
       @import "lib/jquery.countdown/jquery.countdown.css";
    </style>
    <script type="text/javascript">
       $(document).ready(function(){
             var app = new App("mobile_pomodoro");
             app.initialize("timer");
             $("#exit_btn").click(function(evt){
                window.close();
                });

             });
</script>
   </head>




       fisl@urubatancom.br                                  http://www.urubatan.com.br
index.html (2)

  <body>
     <h1 id="header" style="background: url(icon.png) no-repeat;">
        Mobile Pomodoro
     </h1>
     <div id="screen_one" class="screen">
        <div id="timer">
        </div>
        <div id="controls">
           <div id="timer_pomodoro" class="button pomodoro">Start Pomodoro</div>
           <div id="timer_break" class="button break">Take a Break</div>
           <div id="exit_btn" class="button exit">Exit</div>
        </div>
     </div>
  </body>
</html>




      fisl@urubatancom.br                                http://www.urubatan.com.br
basic.css

body {
  font-family:Verdana;
  background-color:#1c1c1c;
  color: #fff;
  margin: 0;
  padding: 0;
}
#header {
    text-indent: 50px;
fisl@urubatancom.br           http://www.urubatan.com.br
basic.css (2)

.button {
    height: 30px;
    line-height: 30px;
    text-align: center;
    text-indent: 30px;
    vertical-align: middle;
    background-repeat: no-repeat;
    right: 20px;
    left: 20px;
fisl@urubatancom.br           http://www.urubatan.com.br
basic.css (3)

.break {
    background-image:
   url('../images/coffee_mug.png');
}
.exit {
    background-image: url('../images/exit.png');
}
#timer {
    background-color: #1C1C1C;
fisl@urubatancom.br            http://www.urubatan.com.br
pomodoro.js

function App(name){
   this.settings = {
      pomodoro_time: 25,
      interval_time: 5
   };
this.history = [];
   this.name = name;
   this.saveSettings = function(){
      if (window.widget) {
          widget.setPreferenceForKey($.toJSON(this.settings), 'settings');
      }
   }
   this.saveHistory = function(){
      if (window.widget) {
          widget.setPreferenceForKey($.toJSON(this.history), 'history');
      }
   }




       fisl@urubatancom.br                                     http://www.urubatan.com.br
pomodoro.js (2)

  this.loadSettings = function(){
     if (window.widget) {
         var rawJSON = window.widget.preferenceForKey('settings');
         if (rawJSON != "" && rawJSON != null && rawJSON != undefined) {
             this.settings = $.evalJSON(rawJSON);
         }
     }
     $(this).trigger("settings_loaded");
  }
  this.loadHistory = function(){
     if (window.widget) {
         var rawJSON = window.widget.preferenceForKey('history');
         if (rawJSON != "" && rawJSON != null && rawJSON != undefined) {
             this.history = $.evalJSON(rawJSON);
         }
     }
     $(this).trigger("settings_loaded");
  }
  this.loadSettings();
  this.loadHistory();
fisl@urubatancom.br                                  http://www.urubatan.com.br
  window.app = this;
pomodoro.js (3)

App.prototype.initialize = function(timer_id){
  window.app.timer_id = timer_id;
  $("#" + timer_id).countdown({
      until: 0,
      format: 'HMS'
  });
  $("#" + timer_id + "_pomodoro").click(window.app.startPomodoro);
  $("#" + timer_id + "_break").click(window.app.startBreak);
  $('body').append('<div id="' + window.app.name + 'player" style="display:none"></div>');
  if (window.menu) {
      window.menu.showSoftkeys();
      var pomodoroMenu = new MenuItem("Start Pomodoro", 101);
      pomodoroMenu.onSelect = function(idx){
         window.app.startPomodoro();
      }
      var breakMenu = new MenuItem("Take a Break", 111);
      breakMenu.onSelect = function(idx){
         window.app.startBreak();
      }
      window.menu.clear();
fisl@urubatancom.br                                   http://www.urubatan.com.br
      window.menu.append(pomodoroMenu);
pomodoro.js(4)

App.prototype.timeUp = function(){
   window.app.playSound();
   window.app.vibrate();
}
App.prototype.startPomodoro = function(evt){
   var time = window.app.settings.pomodoro_time * 60;
   $('#' + window.app.timer_id).countdown("change", {
       until: time,
       format: 'HMS',
       onExpiry: window.app.timeUp
   });
   return false;
}
App.prototype.startBreak = function(evt){
   var time = window.app.settings.interval_time * 60;
   $('#' + window.app.timer_id).countdown("change", {
       until: time,
       format: 'HMS',
       onExpiry: window.app.timeUp
   });
 fisl@urubatancom.br                                  http://www.urubatan.com.br
   return false;
Problemas

   API para menus ainda não disponível multi
    plataforma
          Mas isto raramente é utilizado para dispositivos
           touch screen
   Algumas vezes é necessário adicionar alguns Ifs
    para adicionar código especifico para alguma
    plataforma



fisl@urubatancom.br                http://www.urubatan.com.br
Geolocalization

// onSuccess Callback
// This method accepts a `Position` object, which
   contains
// the current GPS coordinates
//
var onSuccess = function(position) {
   alert('Latitude: '  + position.coords.latitude
   + 'n' +
        'Longitude: '  + position.coords.longitude
fisl@urubatancom.br         http://www.urubatan.com.br
Captura de Imagens

navigator.camera.getPicture(onSuccess, onFail, {
  quality: 50,
  destinationType:
  Camera.DestinationType.FILE_URI });

function onSuccess(imageURI) {
  var image =
  document.getElementById('myImage');
  image.src = imageURI;
fisl@urubatancom.br          http://www.urubatan.com.br
?!?!?!

fisl@urubatancom.br       http://www.urubatan.com.br
Referências
    http://www.urubatan.com.br
    http://phonegap.com
    jQuery Mobile
    JQTouch
    Sencha Touch
    Guarana-UI
    Nokia Web Templates for High-End Devices
    Http://livro.urubatan.com.br



    fisl@urubatancom.br             http://www.urubatan.com.br

Desenvolvendo aplicacoes mobile_com_html_css_

  • 1.
    Desenvolvendo aplicações Mobile com HTML, CSS e JavaScript Aproveitando o conhecimento Web no desenvolvimento Mobile fisl@urubatancom.br http://www.urubatan.com.br
  • 2.
    Palestrante Rodrigo Urubatan (@urubatanno Twitter) trabalha com desenvolvimento de software desde 1997. Já desenvolveu sistemas em uma gama de linguagens e ambientes, incluindo Delphi, C, C++, PHP, ASP, ColdFusion, Assembly, Leather, Ruby e Java. Atualmente trabalha com pesquisa e desenvolvimento na HP, utilizando principalmente Java, Flex e Ruby, e já ministrou cursos e palestras em diversos eventos pelo Brasil. Autor do livro Ruby On Rails: Desenvolvimento Fácil e Rápido de Aplicações Web. fisl@urubatancom.br http://www.urubatan.com.br
  • 3.
    Primeira idéia • Symbiane WebOS suportam aplicações escritas em HTML+CSS+Javascript nativamente • Seria legal fazer o mesmo para Android e iOS • Vou criar um esqueleto de aplicação com WebKit e rodar minha app Symbian WRT no Android! fisl@urubatancom.br http://www.urubatan.com.br
  • 4.
    Esqueleto de aplicação Android Portando WRT para Android fisl@urubatancom.br http://www.urubatan.com.br
  • 5.
    Layout (main.xml) <?xml version="1.0"encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <WebView android:id="@+id/webView" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </LinearLayout> fisl@urubatancom.br http://www.urubatan.com.br
  • 6.
    Activity @Override public void onCreate(BundlesavedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); web = (WebView) findViewById(R.id.webView); WebSettings settings = web.getSettings(); settings.setJavaScriptEnabled(true); settings.setJavaScriptCanOpenWindowsAutomatically(true); settings.setSupportMultipleWindows(true); settings.setSupportZoom(false); settings.setPluginsEnabled(true); web.setVerticalScrollBarEnabled(true); web.setHorizontalScrollBarEnabled(false); // Our application's main page will be loaded web.loadUrl("file:///android_asset/index.html"); } fisl@urubatancom.br http://www.urubatan.com.br
  • 7.
    Port da APIWRT • É necessário expor os objetos da API WRT para a aplicação Android o device o widget o menu • WebView.addJavascriptInterface(objetoJava, “nomeNoJavascript”) fisl@urubatancom.br http://www.urubatan.com.br
  • 8.
    Isto daria muitotrabalho Uma das maiores virtudes dos programadores é a preguiça. fisl@urubatancom.br http://www.urubatan.com.br
  • 9.
    Open Source forthe Rescue Alguem já deve ter feito isto por mim fisl@urubatancom.br http://www.urubatan.com.br
  • 10.
    Opções • PhoneGap o APIs Javascript para acesso a recursos de dispositivos moveis o Suporte para iOS, Android, Symbian, Windoes Mobile, WebOS, Bada (em desenvolvimento), WindowsPhone 7 (em desenvolvimento) o UI desenvolvida com Frameworks JS+CSS o Licensa BSD ou MIT o que for mais conveniente • Titanium Mobile o APIs Javascript para acesso a recursos de dispositivos moveis o Suporte para iOS e Android o API para UI disponivel com L&F nativos o Apache + Comercial para modulos adicionais e suporte fisl@urubatancom.br http://www.urubatan.com.br
  • 11.
    Opção e Motivosda Escolha - 1 • Titanium Mobile o Falta suporte para Symbian o API única para todas as plataformas o API própria para UI o Possibilidade de utilizar quase o mesmo código para gerar aplicações Mobile e Desktop  Nos exemplos apresentados o código é diferente*  Mesmo assim, a possibilidade de compartilhar código é muito interessante o Ambiente de desenvolvimento próprio o Build service - gera aplicação nativa para android e iOS a partir dos fontes enviados (Serviço pago) fisl@urubatancom.br http://www.urubatan.com.br
  • 12.
    Opção e Motivosda Escolha - 2 • PhoneGap o Eu uso e gosto do Symbian o Possui uma API única para todos os dispositivos  Com algumas excessões de coisas que funcionam e uma e não na outra mas isto esta documentado o Eu já conheço gosto de diversos frameworks Javascript o Existem frameworks Javascript que me permitem ter uma UI "nativa" em todas as plataformas o Possibilidade de utilizar a IDE ou editor de textos que me convier o Phonegap Build - serviço que gera apps nativas para todas as plataformas suportadas a partir de um código único (Serviço pago) fisl@urubatancom.br http://www.urubatan.com.br
  • 13.
    Desvantagens • Em ambosos casos é necessário ter os SDKs para cada uma das plataformas instalado na maquina (Exceto se for utilizar o serviço de build) • Em ambos os casos se for necessária para a aplicação uma API não disponível no framework, sera necessário implementar nativamente para cada uma das plataformas desejadas fisl@urubatancom.br http://www.urubatan.com.br
  • 14.
    PhoneGap Meu framework favorito para esta tarefa fisl@urubatancom.br http://www.urubatan.com.br
  • 15.
    APIs nativas disponíveis Acelerometer Camera Capture Compass Connection Contacts Device Events File Geolocation Media Network Notification Storage fisl@urubatancom.br http://www.urubatan.com.br
  • 16.
    Frameworks disponíveis paraUI • jQuery Mobile • jQTouch • Sencha Touch • Guarana-UI • Nokia Web Templates for High-End Devices • Muitos mais pela web ... fisl@urubatancom.br http://www.urubatan.com.br
  • 17.
    Pequeno exemplo • Esteé o código de uma API escrita diretamente para Nokia WRT portada depois para Android utilizando PhoneGap • É uma APP gratuita disponível na OviStore fisl@urubatancom.br http://www.urubatan.com.br
  • 18.
    Mobile Pomodoro fisl@urubatancom.br http://www.urubatan.com.br
  • 19.
    index.html <html> <head> <title>Mobile Pomodoro</title> <link rel="stylesheet" type="text/css" href="css/basic.css"/> <script type="text/javascript" src="lib/jquery.min.js"></script> <script type="text/javascript" src="lib/jquery.json-2.2.min.js"></script> <script type="text/javascript" src="lib/jquery.countdown/jquery.countdown.js"></script> <script type="text/javascript" src="lib/pomodoro.js"></script> <style type="text/css"> @import "lib/jquery.countdown/jquery.countdown.css"; </style> <script type="text/javascript"> $(document).ready(function(){ var app = new App("mobile_pomodoro"); app.initialize("timer"); $("#exit_btn").click(function(evt){ window.close(); }); }); </script> </head> fisl@urubatancom.br http://www.urubatan.com.br
  • 20.
    index.html (2) <body> <h1 id="header" style="background: url(icon.png) no-repeat;"> Mobile Pomodoro </h1> <div id="screen_one" class="screen"> <div id="timer"> </div> <div id="controls"> <div id="timer_pomodoro" class="button pomodoro">Start Pomodoro</div> <div id="timer_break" class="button break">Take a Break</div> <div id="exit_btn" class="button exit">Exit</div> </div> </div> </body> </html> fisl@urubatancom.br http://www.urubatan.com.br
  • 21.
    basic.css body { font-family:Verdana; background-color:#1c1c1c; color: #fff; margin: 0; padding: 0; } #header { text-indent: 50px; fisl@urubatancom.br http://www.urubatan.com.br
  • 22.
    basic.css (2) .button { height: 30px; line-height: 30px; text-align: center; text-indent: 30px; vertical-align: middle; background-repeat: no-repeat; right: 20px; left: 20px; fisl@urubatancom.br http://www.urubatan.com.br
  • 23.
    basic.css (3) .break { background-image: url('../images/coffee_mug.png'); } .exit { background-image: url('../images/exit.png'); } #timer { background-color: #1C1C1C; fisl@urubatancom.br http://www.urubatan.com.br
  • 24.
    pomodoro.js function App(name){ this.settings = { pomodoro_time: 25, interval_time: 5 }; this.history = []; this.name = name; this.saveSettings = function(){ if (window.widget) { widget.setPreferenceForKey($.toJSON(this.settings), 'settings'); } } this.saveHistory = function(){ if (window.widget) { widget.setPreferenceForKey($.toJSON(this.history), 'history'); } } fisl@urubatancom.br http://www.urubatan.com.br
  • 25.
    pomodoro.js (2) this.loadSettings = function(){ if (window.widget) { var rawJSON = window.widget.preferenceForKey('settings'); if (rawJSON != "" && rawJSON != null && rawJSON != undefined) { this.settings = $.evalJSON(rawJSON); } } $(this).trigger("settings_loaded"); } this.loadHistory = function(){ if (window.widget) { var rawJSON = window.widget.preferenceForKey('history'); if (rawJSON != "" && rawJSON != null && rawJSON != undefined) { this.history = $.evalJSON(rawJSON); } } $(this).trigger("settings_loaded"); } this.loadSettings(); this.loadHistory(); fisl@urubatancom.br http://www.urubatan.com.br window.app = this;
  • 26.
    pomodoro.js (3) App.prototype.initialize =function(timer_id){ window.app.timer_id = timer_id; $("#" + timer_id).countdown({ until: 0, format: 'HMS' }); $("#" + timer_id + "_pomodoro").click(window.app.startPomodoro); $("#" + timer_id + "_break").click(window.app.startBreak); $('body').append('<div id="' + window.app.name + 'player" style="display:none"></div>'); if (window.menu) { window.menu.showSoftkeys(); var pomodoroMenu = new MenuItem("Start Pomodoro", 101); pomodoroMenu.onSelect = function(idx){ window.app.startPomodoro(); } var breakMenu = new MenuItem("Take a Break", 111); breakMenu.onSelect = function(idx){ window.app.startBreak(); } window.menu.clear(); fisl@urubatancom.br http://www.urubatan.com.br window.menu.append(pomodoroMenu);
  • 27.
    pomodoro.js(4) App.prototype.timeUp = function(){ window.app.playSound(); window.app.vibrate(); } App.prototype.startPomodoro = function(evt){ var time = window.app.settings.pomodoro_time * 60; $('#' + window.app.timer_id).countdown("change", { until: time, format: 'HMS', onExpiry: window.app.timeUp }); return false; } App.prototype.startBreak = function(evt){ var time = window.app.settings.interval_time * 60; $('#' + window.app.timer_id).countdown("change", { until: time, format: 'HMS', onExpiry: window.app.timeUp }); fisl@urubatancom.br http://www.urubatan.com.br return false;
  • 28.
    Problemas  API para menus ainda não disponível multi plataforma  Mas isto raramente é utilizado para dispositivos touch screen  Algumas vezes é necessário adicionar alguns Ifs para adicionar código especifico para alguma plataforma fisl@urubatancom.br http://www.urubatan.com.br
  • 29.
    Geolocalization // onSuccess Callback //This method accepts a `Position` object, which contains // the current GPS coordinates // var onSuccess = function(position) { alert('Latitude: ' + position.coords.latitude + 'n' + 'Longitude: ' + position.coords.longitude fisl@urubatancom.br http://www.urubatan.com.br
  • 30.
    Captura de Imagens navigator.camera.getPicture(onSuccess,onFail, { quality: 50, destinationType: Camera.DestinationType.FILE_URI }); function onSuccess(imageURI) { var image = document.getElementById('myImage'); image.src = imageURI; fisl@urubatancom.br http://www.urubatan.com.br
  • 31.
    ?!?!?! fisl@urubatancom.br http://www.urubatan.com.br
  • 32.
    Referências  http://www.urubatan.com.br  http://phonegap.com  jQuery Mobile  JQTouch  Sencha Touch  Guarana-UI  Nokia Web Templates for High-End Devices  Http://livro.urubatan.com.br fisl@urubatancom.br http://www.urubatan.com.br