Ontwikkelen met PhoneGap / Cordova

Introductie

PhoneGap is een product gericht op het ontwikkelen van cross-platform/browser web based mobile apps. PhoneGap is een Adobe product wat als open source aan Apache is gedoneerd en daar bestaat onder de naam Cordova. Met PhoneGap wordt grotendeels gewerkt met standaard HTML5, CSS3 en JavaScript. PhoneGap bestaat uit aparte JavaScript frameworks (o.a. jar’s) per mobile platform. Deze bieden voor JavaScripting toegang tot de onderliggende native libraries. Hiermee kan een app grotendeels worden ontwikkeld met gewoon HTML5, CSS3 en JavaScript. De PhoneGap library wordt gedownload en geïnstalleerd vanuit PhoneGap.com.
Het kan ook worden gedownload vanuit GitHub. Op Windows en Mac kan worden gewerkt met Eclipse voor Android (e.a. zoals BlackBerry). Voor iPhone gebruiken we Xcode.

Installatie

Installatie op Mac

Zie ook:PhoneGap Guide for iOS

Installeer Git: download van git-scm.com.

Deze wordt geïnstalleerd onder /usr/local
Ant en Ruby zijn op OSX al geïnstalleerd.
Ga naar developer.apple.com/devcenter.
Ga naar ios onderdeel en download en installeer Xcode.

NB: Lastig Apple fenomeen is dat Xcode alleen via de appstore kan worden verkregen. Om de laatste versie te gebruiken had ik bijv. OSX10.7 (Lion) nodig, en ik zat nog op 10.6 (Snow Leopard). Maar Lion was niet meer te krijgen want de appstore was al op 10.8 (Mountain Lion), en dan is de voorgaande versie gewoon niet meer leverbaar. Die had ik wel nodig want op mijn MacBook (3 jaar oud) kon 10.8 niet meer worden geïnstalleerd. Rare jongens daar bij Apple.

Installatie op Windows

Zie ook : PhoneGap Android Guide

Ruby en ANT (Voor Eclipse gebruik eigenlijk niet nodig)

Android AVD en SDK
Installeer de laatste Android AVD en SDK :

http://developer.android.com/sdk/index.html.

Kies de zip download en installeer de directory onder program files.
Zet de directory in je windows pad. In de root vinden we

  • SDK Manager.exe : tool voor installatie en beheer van aanvullende packages
  • AVD Manager.exe : Android Virtual Device Manager, tool voor testen van Android apps op een gesimuleerd Android device.

Start de SDK Manager.exe en installeer daarmee de verschillende packages die installeerbaar zijn.

We gebruiken SDK manager.exe waarmee we de benodigde packages kunnen downloaden en installeren. Kies alle tools, de laatste Android versie (bijv API 15) met min. één system image, bijv. ARM en kies alles uit de rubriek Extras.

Start de AVD Manager.exe. Geef de AVD een naam, bijv. “BasicEmulator”, Selecteer als target “Google APIs”, 400MB voor de SD card, skin: Default (WVGA800), Enable snapshot. Druk op “Create AVD”. De nieuwe AVD staat nu in de lijst.

Selecteer de BasicEmulator en druk op start. De Android emulator gaat nu opstarten (duurt een tijdje).

Kies boven in het Android scherm (slider naar beneden schuiven) settings en voer de volgende instellingen uit:

  • Onder Security: Unknown Sources : checkbox aan (zorgt ervoor dat apps installatie buiten play store kan)
  • Onder Developer options: USB Debugging : checkbox aan

PhoneGap
Download PhoneGap via http://www.phonegap.com en pak de directory uit.
(Github Alternatief : $ git clone git://github.com/apache/incubator-cordova-android.git)

Installeer Android ADT Plugin in Eclipse:
Voeg binnen Eclipse de repository toe :

http://dl-ssl.google.com/android/eclipse/

noem deze ADT Plugin en installeer deze.

Android projectinrichting Eclipse

Hieronder wordt de aanpak beschreven vanuit Eclipse.
Zie volgende link voor beschrijving via commandline t.b.v. Android:

PhoneGap Guide Android Commandline

Creëer een nieuw Eclipse project, kies daarbij uit de nieuwe Android folder een Android projecttype. Applicatie- en Projectnaam kunnen hetzelfde zijn. Applicatienaam wordt in de Playstore getoond. Er kunnen verschillende instellingen worden gekozen waaronder het minimum platform API versie. De wizard vervolgt met instellingen voor de Launcher icon.
Daarna komen instellingen voor een nieuwe activity waarbij het navigatietype kan worden gekozen. Deze bepaalt hoe de start layout er uitziet. De keuze is afhankelijk van het eerder gekozen Platform API versie. Niet elke versie ondersteunt alle mogelijkheden.

Maak onder de project/applicatie root onder de “assets” directory een nieuwe subdirectory “www”.
Importeer uit de gedownloade PhoneGap uit /lib/android de bestanden cordova.jar en cordova.js.
Zet cordova.jar in de /libs directory en cordova.js onder /assets/libs
Importeer uit de gedownloade PhoneGap de directory /lib/android/xml en zet deze in /res

Onder de nieuwe www directory maak je een index.html file met de volgende inhoud:

<!DOCTYPE html>
<html>
  <head>
    <title>Phonegap Demo</title>
  <script src="cordova-2.1.0.js"></script>
  <script>
     function onLoad(){
          document.addEventListener("deviceready", onDeviceReady, true);
     }
     function onDeviceReady(){
          navigator.notification.alert("Hello, welcome to the PhoneGap world!!");
     }
  </script>
  </head>
  <body onload="onLoad();">
       <h1>Welcome to PhoneGap</h1>
       <h2>Edit assets/www/index.html</h2>
  </body>
</html>

In de [applicatienaam].java file in de /src directory worden de volgende aanpassingen uitgevoerd:

  • Vervang “extends Activity” door “extends DroidGap”
  • Vervang “import android.app.Activity” door “import org.apache.cordova.DroidGap”.

Vervang
“setContentView(R.layout.main)”
door
“super.loadUrl(“file:///android_asset/www/index.html”)”

Nu moet voor PhoneGap in het bestand AndroidManifest.xml, voor de application tag, het volgende worden toegevoegd voor het instellen van de nodige permissies die er voor zorgen dat PhoneGap correct zal draaien:

    <supports-screens
        android:largeScreens="true"
        android:normalScreens="true"
        android:smallScreens="true"
        android:resizeable="true"
        android:anyDensity="true"
        />
        <uses-permission android:name="android.permission.CAMERA" />
        <uses-permission android:name="android.permission.VIBRATE" />
        <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
        <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
        <uses-permission android:name="android.permission.READ_PHONE_STATE" />
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.RECEIVE_SMS" />
        <uses-permission android:name="android.permission.RECORD_AUDIO" />
        <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
        <uses-permission android:name="android.permission.READ_CONTACTS" />
        <uses-permission android:name="android.permission.WRITE_CONTACTS" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Op de <activity> tag wordt het volgende attribuut toegevoegd:

android:configChanges=”orientation|keyboardHidden”

Dit laatste zorgt ervoor dat de applicatie het bestand index.html niet elke keer zal laden bij deze events.

De hiervoor beschreven uitbreidingen/toevoegingen aan de Android projectomgeving zijn niet nodig als gebruik wordt gemaakt van de online command tools voor het creëren van een project.

Draai de applicatie in de emulator met “Run as Android Application”.

Instellen Eclipse projectfacets voor JavaScript / Java

Voor het project is het handig om de Eclipse projectfacets in te schakelen voor JavaScript en Eclipse. Dat gaat op de gebruikelijke wijze via Projectmenu Properties->Facets.
Daarbij moet rekening worden gehouden met de Java JDK versie. Deze moet mogelijk worden ingesteld op versie 1.5. Er kunnen foutmeldingen hierover komen in Markers view van Eclipse. Dat kan bijv worden opgelost door de Project menu Android Tools en dan item Fix Project Properties te kiezen. Deze zal dan de Java compiler instellen op het compliance nivo wat hoort bij de Android JDK versie. Dit kan vervolgens leiden tot foutmeldingen over de verkeerde Java JDK instelling in het project facet voor Java. Deze pas je dan vervolgens aan.

Een ander probleem wat kan ontstaan zijn JavaScript syntax foutmeldingen over jQuery Mobile. Deze worden uitgeschakeld door het betreffende jQuery bestand voor JavaScript validatie uit te schakelen. Dat doe je als volgt:
Kies projectmenu properties, dan optie JavaScript (is er alleen als projectfacet JavaScript is aangezet), en ga dan naar optie Include Path, en daarbinnen selecteer je de categorie “Excluded”, druk dan op Edit en voeg het betreffende bestand toe.

PhoneGap Ontwikkeling

PhoneGap Basis Projectstructuur

De basis structuur van een PhoneGap project bestaat uit de volgende onderdelen die onder de projectroot zijn te vinden:

  • /AndroidManifest.xml : beschrijft de nodige configuratie zaken van de mobile app.
  • /assets/www : directory met de html bestanden en de phonegaps js library : cordova-2.1.0.js
  • /libs : directory met gebruikte libraries zoals de phonegap library : cordova-2.1.0.jar.
    Ook aanwezig : android-support-v4.jar
  • /res: directory met allerlei resources zoals plaatjes, layout configuraties, menu configuraties. Hierin bevinden zich ook de plaatjes die als opstart icon op het device worden getoond.
  • /src : directory met de Java sources, georganiseerd in sub-directory structuur conform de package definities (bijv. com.biz.). Hierin bevindt zich ook het java bestand voor de applicatie die het laden van de index.html verzorgt, en daarmee de start van de PhoneGap HTML5/CSS3/JavaScript app.
  • /bin : directory met build output

Verder kunnen zich er nog allerlei build.xml, classpath bestanden en properties bestanden, etc. bevinden, afhankelijk van de gebruikte tooling (Eclipse, Ant, etc.).

De “[app].java applicatie” class

In de /src directory vinden we het volgende Java class voorbeeld die de Android opstart van de PhoneGap app regelt. Daarna vindt eigenlijk alles in HTML/CSS3/JavaScript plaats. Dit bestand is voor PhoneGap aangepast met de “extends DroidGap” waarmee de “loadUrl()” call voor het starten van de index.html kon worden toegevoegd i.p.v. de default Android “setContentView()” call. Ook nodig was de import van org.apache.cordova.DroidGap.

package org.biz.mobileclient;

import org.apache.cordova.DroidGap;
import android.os.Bundle;
import android.view.Menu;

public class Departments extends DroidGap {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setContentView(R.layout.activity_departments);
        super.loadUrl("file:///android_asset/www/index.html");
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_departments, menu);
        return true;
    }
}

AndroidManifest.xml

Dit bestand beschrijft de nodige configuratie zaken van de mobile app.
Zo zien we de package naam, gebruikte sdk versies, de permissies, gebruikte labels, icon, theme, en de main activity die refereert naar de opstart Java class (Department.java in dit voorbeeld) in de src directory. etc.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="org.biz.mobileclient"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="15" />
    <supports-screens
        android:largeScreens="true"
        android:normalScreens="true"
        android:smallScreens="true"
        android:resizeable="true"
        android:anyDensity="true"
        />
        <uses-permission android:name="android.permission.CAMERA" />
        <uses-permission android:name="android.permission.VIBRATE" />
        <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
        <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
        <uses-permission android:name="android.permission.READ_PHONE_STATE" />
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.RECEIVE_SMS" />
        <uses-permission android:name="android.permission.RECORD_AUDIO" />
        <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
        <uses-permission android:name="android.permission.READ_CONTACTS" />
        <uses-permission android:name="android.permission.WRITE_CONTACTS" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".Departments"
            android:label="@string/title_activity_departments"
            android:configChanges="orientation|keyboardHidden" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

index.html

Het index.html bestand is het startpunt van de app.
In onderstaand voorbeeld zien we de javascript toevoegingen zoals :

  • de cordova-2.1.0.js library
  • een onLoad() event voor het body element die de eventlistener “onDocumentReady()” toevoegt
  • een onDocumentReady() eventlistener die een alert toont.
<!DOCTYPE html>
<html>
  <head>
  <title>Phonegap Demo</title>
  <meta name="viewport" content="width=device-width, initialscale=1.0, user-scalable=no"></meta>
  <link rel="stylesheet" type="text/css" media="screen" href="main.css" />
  <script src="cordova-2.1.0.js" type="text/javascript"></script>
  <script type="text/javascript">
     document.addEventListener("DOMContentLoaded", onDocumentReady, true);
     function onDocumentReady(){
		alert("PhoneGap is working!!");
     }
  </script>
  </head>
  <body>
       <h1>Welcome to PhoneGap</h1>
  </body>
</html>

Deze opzet lijkt veel op het gebruik van jQuery waarbij ook een initieel Document load() event wordt gebruikt als startpunt om de JavaScript inhoud en gedrag (i.c.m. HTML5/CSS3) van de pagina verder invulling te geven.

In de body zit in dit voorbeeld alleen welkomsttekst. Hier wordt de verdere content vormgegeven met html elementen die met css wordt gestyled en verder met JavaScript voorzien van verdere dynamische content en gedrag.

Events en Event Listeners

PhoneGap heeft als startpunt een event nodig waar aanvullende JavaScript kan worden toegevoegd voor de inhoud en gedrag van de pagina. Uiteraard in combinatie met html5 en css3 elementen. Er wordt gebruik gemaakt van de standaard JavaScript functie “addEventListener()”.

[object].addEventListener(eventtype, listener, ..)

Het object kan van alles binnen het DOM domain zijn zoals document, window, etc.
Het eventtype definieert het event waarnaar wordt geluisterd.
De listener is de functie die wordt aangeroepen als het event optreedt.

Een veel gebruikt event type voor initieel starten van de applicatie is “DOMContentLoaded”.
Voorbeeld van andere standaard eventtypes : mousedown, mouseup, keypress , keydown, keyup, blur, hover, etc. Zie voor overzicht van de JavaScript eventtypes :

https://developer.mozilla.org/en-US/docs/DOM/DOM_event_reference

Hieronder een voorbeeld waarmee een EventListener “DOMContentLoaded” wordt toegevoegd. Deze wordt geactiveerd door het moment waarop het DOM document is geladen.
De EventListener roept de function “onDocumentReady()” aan die een alert toont dat PhoneGap werkt en vervolgens een nieuwe EventListener toevoegt aan een button element met id “btnHello”, gekoppeld aan het click event. Het button element wat in de body zit zal bij de click event hierdoor de functie sayHello() aanroepen.

<script type="text/javascript">
     document.addEventListener("DOMContentLoaded", onDocumentReady, true);
     function onDocumentReady(){
        //navigator.notification.alert("PhoneGap is working!!");
		alert("PhoneGap is working!!");
 		document.getElementById("btnHello").addEventListener("click", sayHello, false);
     }
     function sayHello() {
    	 alert("Hello dear Phonegap fan!!!");
     }
</script>

<button id="btnHello">Say Hello</button>

PhoneGap voegt aan de standaard events ook mobiel specifieke events toe.
De belangrijkste daarvan is deviceready die i.p.v. DOMContentLoaded wordt gebruikt.
Deze treedt op wanneer het mobile device gereed is voor verdere processing:

addEventListener("deviceready  ", onDeviceReady, true);

Dit is echter een event wat alleen in de mobile omgeving (of emulator) werkt.
Om in de browser te testen gebruik je “DOMContentLoaded”.

Overzicht van de belangrijkste PhoneGap event types :

  • deviceready : moment waarop de mobiel aanspreekbaar is voor de applicatie
  • pause : moment waarop de applicatie naar de achtergrond wordt gezet
  • resume : moment waarop de applicatie weer wordt geactiveerd
  • online : moment waarop de mobiel internet verbinding krijgt
  • offline : moment waarop de mobiel internet verbinding verdwijnt.
  • backbutton : voor android/blackberry het gebruiken van de back-toets
  • menubutton : voor android/blackberry het gebruiken van de menu-toets
  • searchbutton : gebruik van de search toets

Met de menubutton kunnen dus menu items worden getoond. Dat is echter niet iets wat eenvoudig wordt ondersteund in PhoneGap. Zeker niet als je graag zoiets als de native look&feel van Android menu’s wilt tonen. Dit kan wel, zie:

https://github.com/mwbrooks/cordova-plugin-menu

Alerts en PhoneGap Alerts

De alert() functie is de standaard JavaScript functie.
Je kunt ook gebruikmaken van de PhoneGap versie

navigator.notification.alert(“Message", function() {}, "Title");

Deze message is asynchroon, d.w.z. niet blokkerend, en er kan een dialogtitel worden gedefinieerd. Helaas werkt deze in de browser niet.

Viewport gebruik

De Viewport is een intermediair component tussen de applicatiewindows en de gebruiker in. Deze behandelt de schaling van de window naar het device toe. De CSS instellingen zien hier ook van belang (zie volgende paragraaf). De viewport wordt ingesteld met een specifieke meta tag in de head, zie voorbeeld:

<meta name="viewport" content="width=device-width, initialscale=1.0, user-scalable=no"></meta>

Deze tag instelling zorgt er voor dat een web gebaseerd html ontwerp zich op een mobiel device presenteert als een standaard app, d.w.z. een vast window. De bovenstaande instellingen regelen dat en houden het volgende in:

  • Pas breedte aan aan het device
  • Voer geen initiele schaling toe, de applicatie regelt dat zelf
  • De gebruiker kan niet schalen

CSS Styling aspecten (Responsive Design)

De CSS styling wordt bij voorkeur in aparte css bestanden gestopt. Hieronder een voorbeeld van een de css definities voor de eerder beschreven index.html:

index.html stylesheet referentie:

<link rel="stylesheet" type="text/css" media="screen" href="main.css" />

index.html body content:

  <body>
  <div id="main" class="box rounded">
       <h1>Welcome to PhoneGap</h1>
       <button id="btnHello">Say Hello</button>
  </div>
  </body>

main.css stylesheet

@CHARSET "ISO-8859-1";
html {
   height: 100%;
}
body {
   height: 96%;
   background: #ff0;
}
.box {
   background: #ccf;
   width: 80%;
   padding: 10%;
   height: 90%;
}
.rounded {
   -webkit-border-radius: 8px; /* webkit specific */
   border-radius: 8px; /* generic */
}

De body krijgt een gele achtergrond en daarbinnen het div element een grijs/blauwe achtergrond.


Het div element heeft beide css classes “box” en “rounded” gedefinieerd.

  • box class : zorgt voor de grijsblauwe achtergrond en de relatieve afmetingen.
  • rounded class : zorgt voor afgeronde hoeken.

De box class gebruikt percentages om de afmeting van de grijsblauwe box binnen de gele achtergrond te laten schalen naar de device afmeting (Responsive design). Door de 80% breedte en de 10% padding blijft deze netjes in het midden van het gele veld en krijgt het daardoor visueel een 5% gele rand.

De verticale “height” afmeting is een bijzonder verhaal. Deze werkt alleen goed als ook de afmeting van de html en body elementen worden ingesteld. Dat komt omdat alles feitelijk is gebaseerd op een geneste set containers: body binnen html en div binnen body.
Nu betekent de 90% div hoogte : 90% van de container waar deze in ligt: de body. Maar als de parent container body geen hoogte specificatie heeft dan zegt dat niets. Hetzelfde geldt voor body t.o.v. html. Dus worden ook hoogtes gedefinieerd voor html en body.
In dit geval kon het body element geen 100% krijgen, want dat veroorzaakt een vertikale scrollbar, waardoor de inliggende body iets kleiner moet worden dan de parent html.
Met trial & error wordt uiteindelijk de hoogte van div op 90% bepaalt om een nette rand te krijgen.

-webkit notatie

Specifieke css properties die zijn bedoeld voor mobile platforms worden geprefixed met “-webkit”. Als ze regulier onderdeel zijn geworden van de meeste browsers is de property ook beschikbaar zonder de prefix. Zo worden in voorgaand voorbeeld de volgende properties gebruikt om een block element afgeronde hoeken te geven:

  • -webkit-border-radius
  • Border-radius.

Ajax, JSON en Remote REST Webservices

Onderstaand voorbeeld voert een Ajax call uit naar een REST webservice.

  <script type="text/javascript">
     document.addEventListener("DOMContentLoaded", onDocumentReady, true);
     function onDocumentReady() {
		var req = new XMLHttpRequest();
		req.onreadystatechange = function () {
		   if (this.readyState == 4) {
			if (this.status == 200) {
	    	 	var data = JSON.parse(this.responseText);
	    	 	var ul = document.getElementById("dplist");
	    	 	console.log("test 3, length=" + data.rows.length);
	    	 	for (var i=0; i < data.rows.length; i++) {
		    		var item = document.createElement("li");
		    		item.innerHTML = data.rows[i].name;
	    	 		ul.appendChild(item);
	    	 	}
	    		}
    		   }
		}
    		req.open("POST", "http://localhost:8082/JEE62/dep/list", true);
    	req.send();
     }
  </script>

  <body>
  <div id="main" class="box rounded">
       <h1>Departments</h1>
       <ul id=dplist>
       </ul>
  </div>
  </body>

De onDocumentReady eventlistener bevat de implementatie van de Ajax call.
Deze maakt het XHR object en hangt hieraan een callback functie aan het event “onreadystatechange”. Als de juiste status is ontvangen wordt de ontvangen json string uit de responseText geparsed en aan de variabele “data” opgeslagen.
Vervolgens worden de records uit het JSON object in data variabele in een loop langsgelopen om hiermee list items aan te maken. Aan het eind van de onDocumentReady eventlistener wordt het request daadwerkelijk verstuurd.

NB: Voor testen op de Android Emulator kan localhost niet worden gebruikt. Dan moet het ip-adres worden gebruikt.

Voor de JSON functionaliteit moet een JSON library worden gedownload en toegevoegd.
(https://github.com/douglascrockford/JSON-js/downloads)
In gewone webbrowsers zit deze functionaliteit standaard, maar niet in mobiele browsers.

Nu zijn er nogal wat problemen bij het versturen van dit REST webservice request, en dat heeft te maken met zgn. “Cross Domain” beperking die geldt voor url benadering vanuit JavaScript in Browsers. De volgende paragraaf gaat op dit onderwerp in.

Cross Domain Browser URL probleem

Er ontstaan problemen als JavaScript vanuit een browser een url wil aanroepen die niet in het eigen domein ligt. Dit probleem heeft een beveiligingsoorzaak.
Om dit probleem op te lossen moeten in de header van de server responses een aantal properties worden meegegeven:

Access-Control-Allow-Origin = *
Access-Control-Allow-Credentials = true

Om dat te bereiken wordt een servlet filter toegevoegd die dit voor alle requests doet. Dit is een class die het javax.servlet.Filter interface implementeert zoals in voorbeeld hieronder:

public class XDR implements javax.servlet.Filter {
	@Override
	public void destroy() {
	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
                                             throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) resp;

	    response.addHeader("Access-Control-Allow-Origin", "*");
	    if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
	        response.addHeader("Access-Control-Allow-Credentials", "true");
	    }
	    chain.doFilter(req, resp);
	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {
	}
}

Dit filter moet worden gekoppeld aan het servlet pad van de webservice. Dat wordt gedaan door dit in de deployment descriptor web.xml te configureren:

  <filter>
    <filter-name>XDR</filter-name>
    <filter-class>org.biz.rest.XDR</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>XDR</filter-name>
    <url-pattern>/dep/list</url-pattern>
  </filter-mapping>

In bovenstaand voorbeeld wordt het XDR filter gekoppeld aan een specifiek pad /dep/list.
Hier kunnen ook wildcards worden toegepast door dit te veranderen in /dep/* of zelfs /*.
In dat laatste geval zullen alle servlet en REST webservices paden het filter uitvoeren.

Cross Domain bij jQuery
Het probleem kan, bij gebruik van jQuery, ook worden opgelost met jQuery instellingen.
jQuery heeft een $.support.cors boolean dat aangeeft of jQuery denkt dat de browser de W3C “Cross-Origin Resource Sharing” feature ondersteunt voor cross-domain requests.
Bij gebruik van jQuery $.ajax() moet de $.support.cors boolean op true worden gezet.

Query, Ajax en REST Webservices

jQuery is de meest gebruikte JavaScipt library (http://jquery.com/).
Voor mobiele applicaties kan deze nogal zwaar zijn, en kan als alternatief worden gekozen voor XUI (http://xuijs.com/).

Als jQuery wordt gebruikt, moet het jQuery.js bestand worden toegevoegd in de webfolder en in de head van de gebruikmakende html’s worden gespecificeerd:

  <script type="text/javascript" src="jquery-1.8.2.min.js"></script>

Hieronder wordt een voorbeeld getoond van het aanroepen van dezelfde REST webservice als in eerder voorbeeld met native Ajax gebruik met het XHR object. Nu wordt de jQuery $.ajax functie gebruikt, en tevens de jQuery functies om over het resulaat te itereren en de html elementen te addresseren:

<script type="text/javascript">
/*  $(document).ready(function () {*/
  document.addEventListener("DOMContentLoaded", onDocumentReady, true);
  function onDocumentReady() {
      jQuery.support.cors = true;
      $.ajax(
          {
              type: "POST",
              url: "http://192.168.0.192:8082/JEE62/dep/list",
              dataType: "json",
              success: function (data) {
                  $.each(data.rows, function (i, item) {
                      $("#dplist").append('<li id="' + i + '">' + item.name + '</li>');
                  });
              },
              error: function (jqXHR, textStatus, errorThrown) {
            	  console.log('error trapped in error: function(jqXHR, textStatus, errorThrown)');
            	  console.log('XHRstatus = ' + jqXHR.status +
                              ' XHRreadyState = ' + jqXHR.readyState +
                              ', textStatus = ' + textStatus + ', errorThrown = ' + errorThrown);
              }
          });
  }
  </script>
  </head>

Normaal gesproken maakt jQuery gebruik van zijn eigen event opzet:

$(document).ready(function() {}) .

Hier is er voor gekozen om gebruik te maken van de standaard eventlisteners opzet.

De jQuery $.ajax functie bevat alle ingredienten : aanroep en afhandeling resultaat.
Als input worden de volgende elementen gespecificeerd:

  • type : request type POST, GET etc ingesteld.
  • url: de url van de server functie, in dit geval een REST webservice.
  • dataType: verwacht resultaattype, kan o.a. zijn : xml, json, text, (en meer: script, jsnop, multiple).
  • success: de functie die het resultaat verwerkt bij success
  • error: de functie die de foutsituaties afhandelt.

Aanvullende mogelijkheden om ook data mee te sturen met de request, bijv:

  • data: “{name: “John”, location: “Boston”}”
  • contentType: bepaalt de formaat van de verstuurde data.

Default is “application/x-www-form-urlencoded; charset=UTF-8″.

Er zijn vele andere Ajax call mogelijkheden , zie : http://api.jquery.com/jQuery.ajax/

Loggen en Testen

Testen gebeurt deels in de browser en deels op een mobile phone emulator zoals Android’s AVD of de iOS Iphone/IPAd emulators binnen Xcode.

Binnen de browser wordt vooral gewerkt om gebruik te kunnen maken van de debuggers, logging en overige ontwikkelfaciliteiten. FireFox is voor dit doel een geschikte browser met name om de Firebug debugging extensie. Verder werkt het ontwikkelen en testen binnen de browser ook zeer snel omdat je direct kunt zien wat je ontwikkelt. In FireFox is ook de Responsive Design weergave erg handig, waarmee je de schermafmeting kunt simuleren en daarmee afstemmen op je mobiele doel platform. Een handige manier van werken is om met Eclipse de html, css en JavaScript sources te ontwikkelen en zo gebruik te maken van de grafische editing en ondersteunende faciliteiten. De opgeslagen sources kun je dan direct testen door de html pagina’s direct binnen de Eclipse workspace op het filesysteem in je browser te openen.

Binnen de JavaScript sources kun je loggen met console.log(). De output komt terecht in een console view die onderdeel is van de browser. Ook in FireBug wordt de log output zichtbaar.

This entry was posted in Mobile and tagged . Bookmark the permalink.

Geef een reactie

Je e-mailadres wordt niet gepubliceerd.

De volgende HTML tags en attributen zijn toegestaan: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>