Open Source im professionellen Einsatz
Linux-Magazin 05/2015
© Alexey Klementiev, Fotolia, 123RF

© Alexey Klementiev, Fotolia, 123RF

Apps für Firefox OS entwickeln

In sich stimmig

Erst Apps bringen die Smartness aufs Smartphone, da macht Firefox OS keine Ausnahme. Im Unterschied zur Konkurrenz bauen die Entwickler ihre Apps jedoch mit offenen Webtechnologien wie HTML 5, Javascript und CSS 3. Der Artikel zeigt das exemplarisch anhand einer App zum Stimmen von Gitarren.

1860

Theoretisch gibt es Millionen von Firefox-Apps. Anders als bei den Platzhirschen Android und I-OS kann ein Entwickler Webseiten einfach aus dem Internet herunterladen, sie in eine App [1] verwandeln und unter Firefox OS lokal auf dem Gerät einsetzen. Wie das in der Praxis aussieht, verdeutlicht der Artikel anhand einer einfachen Beispiel-App, die HTML 5, Javascript, das Webaudio-API, Jquery sowie CSS 3 kombiniert.

So eine Anwendung lässt sich unter Ubuntu 12.04 bequem im Firefox-Browser als Webapp entwickeln und testen. Im Erfolgsfall macht der Entwickler aus der Web- eine Firefox-OS-App und prüft ihre Praxistauglichkeit im Simulator.

Tonangebend

Die Beispiel-App, eine Software namens Firemerl, hilft Musikern dabei, ihre Gitarren zu stimmen. Abbildung 1 zeigt sie als Desktop-Variante unter Firefox 35.1 auf Ubuntu 12.04. Der Gitarrist bedient die App über die vertikale Knopfleiste in der Mitte der Abbildung. Drückt er auf einen Knopf, erzeugt Javascript mit Hilfe des Webaudio-API einen Dauerton in der gewählten Tonhöhe. Ein erneuter Klick auf einen anderen Knopf ändert die Tonhöhe. Ein Klick auf den gleichen Knopf stoppt die Tonausgabe. Will er sein Instrument stimmen, variiert der Musiker über die Stimm-Mechanik am Gitarrenkopf jeweils die Tonhöhe der Gitarrensaite, bis diese hörbar in dem vom Gerät erzeugten Referenzton schwingt.

Abbildung 1: Die Webapp Firemerl, hier in der Browseransicht von Firefox 35.1, dient als Beispiel für eine Firefox-OS-App, die auf standardisierten Webtechnologien beruht.

Programmieren lässt sich Firemerl zum Beispiel mit dem Open-Source-Editor Geany [2], Abbildung 2 zeigt die grafische Benutzerschnittstelle mit vier offenen Tabs. Der Editor eignet sich prima für kleinere Projekte und bietet alle Features eines professionellen Programmiertools an. Dazu gehören Syntax Highlighting für eine Vielzahl von Sprachen, Zeilen- und Spaltennummern, mehrere Formen der Codevervollständigung sowie eine ausgefeilte Suchen-und-Ersetzen-Funktion. Daneben unterstützt Geany ein Versionskontrollsystem für Quellcode und arbeitet direkt mit dem Dateisystem.

Abbildung 2: Geany hält alle wesentlichen Dateien der Beispiel-App in verschiedenen Tabs bereit.

Den Editor, der unter der GPLv2 steht, erweitert bei Bedarf eine Reihe von Plugins, beispielsweise ein Baumnavigator und eine Rechtschreibprüfung, die der Anwender direkt aus dem Menü heraus installiert. Um den Buildprozess für eine Software anzustoßen, definiert der Benutzer externe Befehle und führt diese dann aus. Unter Ubuntu 12.04 spielt der Befehl »sudo apt-get install geany« die Software auf den Rechner.

Listing 1 zeigt das Webinterface der Beispiel-App, das die Datei »index.html« erzeugt. Das HTML-5-Dokument bindet in seinem Kopf die Stylesheet-Angaben aus der Datei »css/app.css« ein (Zeile 5) sowie eine aktuelle Kopie der Open-Source-Javascript-Bibliothek Jquery (Zeile 6, [3]). In Zeile 7 folgt der Javascript-Code, der die Anwendungslogik der Beispiel-App enthält, die in der Datei »js/app.js« steckt. Alle drei Ressourcen liegen als Dateien in der Verzeichnisstruktur der App, die Listing 3 zeigt, und sind relativ zu »index.html« verlinkt.

Listing 3

Lokale Verzeichnisstruktur der App

01 src
02 |- css
03 |       |- app.css
04 |- img
05 |       |- icon-128.png
06 |       |- icon-24.png
07 |- js
08 |       |- app.js
09 |       |- jquery.js
10 |- index.html
11 |- manifest.webapp

Listing 1

Das HTML-5-Webinterface der index.html

01 <!DOCTYPE html>
02 <html>
03 <head>
04         <meta charset="utf-8">
05         <link href="css/app.css" rel="stylesheet"></link>
06         <script src="js/jquery.js"></script>
07         <script src="js/app.js"></script>
08 </head>
09 <body>
10         <div id="container">
11                 <h1><img src="img/icon-24.png"/>FireMerl</h1>
12                 <h2>Stimmgerät</h2>
13                 <input type="button" value="E"/>
14                 <input type="button" value="A"/>
15                 <input type="button" value="d"/>
16                 <input type="button" value="g"/>
17                 <input type="button" value="h"/>
18                 <input type="button" value="e'"/>
19         </div>
20 </body>
21 </html>

Der Körper von »index.html« speichert ab Zeile 13 eine Folge von Buttons, über die der Benutzer die Tonauswahl trifft. Auf Knopfdruck liest eine Rückruffunktion in Javascript die Tonhöhe aus dem »value« -Attribut des DOM-Objekts, das den Knopf repräsentiert, beispielsweise ein "E" oder "e'".

Listing 2 zeigt den Javascript-Code der Datei »js/app.js« . Hat der Browser das HTML-Dokument vollständig geladen, ruft er die Funktion aus Zeile 1 im Stile einer Rückruffunktion auf. Die speichert in den folgenden vier Zeilen Variablen, welche die Funktion ab Zeile 6 zur Laufzeit verwendet.

Listing 2

Hier spielt die Musik (js/app.js)

01 $(document).ready(function() {
02         var ctx = new window.AudioContext(),
03                 osc = undefined,
04                 prev = undefined,
05                 freqs = {E: 82.4, A: 110, d: 146.8, g: 196, h: 246.9, "e'": 329.6};
06         $('input[type=button]').click(function() {
07                 var act = $(this);
08                 if (osc)
09                         osc.stop(0);
10                 if (prev)
11                         prev.removeClass('highlighted');
12                 if (prev === undefined || act.val() !== prev.val()) {
13                         prev = act;
14                         osc = ctx.createOscillator();
15                         osc.connect(ctx.destination);
16                         osc.frequency.value = freqs[prev.val()];
17                         osc.start(0);
18                         prev.addClass('highlighted');
19                 } else
20                         prev = undefined;
21         });
22 });

Der Javascript-Code bindet Variablen lexikalisch und hat in der Hauptfunktion ab Zeile 1 bereits die Variablen aus den Zeilen 2 bis 5 sowie die Funktion ab Zeile 6 definiert. Daher kann jeder Aufruf der zweiten Funktion die zur Laufzeit in den Variablen gespeicherten Werte auslesen und verändern. Auf diese Art teilen asynchrone Funktionsaufrufe Daten unter Verzicht auf globale Variablen. Weil die Variablendefinitionen ab Zeile 2 das Schlüsselwort »var« verwenden, sind sie außerhalb des Funktionsrumpfes (Zeilen 1 bis 22) zugleich unsichtbar.

In Zeile 6 behält die Funktion »$()« dank des CSS-Selektors »'input[type=button]'« alle DOM-Objekte aus dem HTML-Dokument im Auge, die Knöpfe repräsentieren. Die Methode »click()« vereinbart anschließend für jeden zuvor mit »$()« ausgewählten Button die Funktion aus Zeile 6 als Rückruffunktion. Dabei arbeitet »click()« gemäß dem Entwurfsmuster Komposition: Sie funktioniert gleichermaßen für ein einzelnes oder eine Liste von Objekten.

Die Rückruffunktion speichert in der Variablen »act« (Zeile 7) zunächst eine Referenz auf das DOM-Objekt, das den eben angeklickten Knopf repräsentiert. Die Funktion »$()« erzeugt diese Referenz unter Einsatz der Sondervariablen »this« . In Zeile 9 beendet das Skript die Tonausgabe über das Oszillator-Objekt, indem es die Methode »stop()« aufruft. Dank Zeile 11 hebt der Browser den zuletzt gedrückten Knopf nicht mehr gelb hervor (Abbildung 6), weil die Jquery-Methode »removeClass« einfach die CSS-Klasse »highlighted« als Formatierung des DOM-Objekts aus »prev« löscht.

Abbildung 6: Firemerl lässt Musiker ihre Gitarren stimmen.

Zeile 12 startet nur dann eine erneute Tonausgabe, wenn der Anwender einen anderen Knopf gedrückt oder die App zuvor keinen Ton ausgegeben hat. Trifft eine der beiden Voraussetzungen zu, merkt sich Zeile 13 in der Variablen »prev« zunächst eine Referenz auf den noch auszugebenden Ton für den späteren Aufruf. Zeile 14 erzeugt mit der Variablen »ctx« , einer Instanz des Webaudio-API, ein Oszillator-Objekt und speichert es in der Variablen »osc« . Die nächste Zeile verbindet die Tonausgabe des Oszillator-Objekts mit dem Lautsprecher »ctx.destination« , die übernächste stellt über das Map-Objekt »freqs« (Zeile 5) die gewünschte Frequenz ein. Zeile 17 ruft die Methode »start()« auf und gibt so den Ton aus.

Abschließend hebt Zeile 18 den soeben gedrückten Knopf im Browser gelb hervor, indem sie das entsprechende DOM-Objekt mit der CSS-Klasse »highlighted« formatiert. Wird in Zeile 12 hingegen keine Tonausgabe gestartet, löscht Zeile 20 die Variable »prev« und setzt die Anwendung in den anfänglichen Zustand "Bisher kein Ton gespielt" zurück.

Reformation

Der Schritt, der die Webapp aus Abbildung 1 in die Firefox-OS-App aus Abbildung 6 verwandelt, ist klein, wenn der Entwickler den lokalen Charakter der Firefox-OS-App bereits beim Entwickeln der Webapp berücksichtigt. Listing 3 zeigt die Verzeichnisstruktur der Beispiel-App. Im Gegensatz zu einer Webapp, die etwa Webfonts, Zählmarken oder Javascript-Add-ons von externen Webservern lädt, speichert die Beispiel-App alle Ressourcen lokal. Zwar kann die App unter Firefox OS auch Dateien oder Anwendungsdaten aus dem Internet nachladen, doch würde sie bei Internetstörungen oder im Offline-Modus nur eingeschränkt oder gar nicht funktionieren.

Im Gegensatz zur Webapp enthält eine Firefox-OS-App ein Manifest, das Firefox OS über die Eigenschaften der App informiert. Listing 4 zeigt das Manifest der Beispiel-App. Die Datei »manifest.webapp« speichert Daten im Json-Format. Die Spezifikationen für Webapps [4] beschreiben die verwendeten Felder und ihre Werte, das Dokument benennt nur wenige Pflichtfelder.

Listing 4

manifest.webapp

01 {
02         "name": "FireMerl",
03         "description": "Stimmgerät für Gitarren",
04         "launch_path": "/index.html",
05         "icons": {
06                 "128": "/img/icon-128.png"
07         },
08         "developer": {
09                 "name": "P. Andreas Möller",
10                 "url": "http://pamoller.com"
11         },
12         "default_locale": "de",
13         "type": "web"
14 }

Das Manifest aus Listing 4 enthält alle Angaben, die nötig sind, um die App über den App-Store von Firefox zu vertreiben. Das Feld »name« speichert den Namen der App, »description« eine kurze Beschreibung, »launch_path« den Pfad der Datei, die Firefox OS beim Start der App aufrufen soll. Das Feld »icons« verweist auf eine Sammlung von Icons, die Mozillas OS kontextspezifisch einsetzt, beispielsweise als Desktop-Icon.

Die App verlangt ein quadratisches Icon in einer Größe von 128 Pixel. In das Feld »developer« kommen der Name und die Homepage des Entwicklers, »default_locale« gibt die Standardsprache der App an. Das Feld ist nur obligatorisch, wenn die App mehrsprachig ist.

Unter »type« verrät der Entwickler den Anwendungstyp. Das Feld betrifft lediglich den Vertrieb über den App-Store von Firefox. Zusammen mit den Informationen aus dem Feld »permissions« validieren die Shopbetreiber die Sicherheit und die Fairness der App. Greift die nämlich auf Schnittstellen zu, die Firefox als systemnah [5] begreift, zum Beispiel das Adressbuch oder die Verbindungsschicht TCP, muss das Feld »type« den Wert »privileged« enthalten. Privilegierte Apps macht Mozilla seinen Kunden erst nach eingehender Prüfung im App-Store verfügbar.

Verwendet die App systemkritische Schnittstellen und greift etwa auf das Bluetooth-Modul oder den SMS-Dienst zu, muss in dem Feld »certified« stehen. Zwar darf jeder solche Apps herstellen und verwenden, doch sie dürfen nicht in den App-Store. Ihr Vertrieb bleibt Mozilla und den Partnern vorbehalten.

Nutzt eine App privilegierte oder interne APIs, muss der Entwickler dies im Manifest deklarieren. Listing 5 zeigt am Beispiel von Cors (Cross Origin Requests), wie er ein privilegiertes API anspricht. Dazu speichert das Feld »type« zunächst den Wert »privileged« . Zeile 3 enthält den Bezeichner »systemXHR« als Schlüsselwert im Feld »permissions« , was den Einsatz von Cors anzeigt. Der Verwendungszweck gehört in das Feld »description« .

Listing 5

Privilegiert oder interne APIs (Auszug)

01 "type": "privileged",
02 "permissions": {
03         "systemXHR": {
04                 "description": "Use web fonts."
05         }
06 }

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 5 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

Linux-Magazin kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • App-Store nach Mozilla-Art entsteht

    Die Mozilla Foundation ist dabei, neben den Firefox-Versionen für mobile Geräte auch einen eigenen App-Service zu entwickeln.

  • HTML 5 offline

    Ein Offlinespeicher im Browser und ein Schuss HTML-5-Akrobatik ergeben interaktive Webanwendungen, die auch dann noch funktionieren, wenn die Internetverbindung abreißt. Als Kür zaubert das folgende Beispiel ein GUI, das auf Desktops wie Smartphones eine gute Figur macht.

  • Firefox Developer Edition ersetzt Aurora

    Von Mozilla groß angekündigt, ist diese Woche Firefox Developer Edition erschienen, eine Version des Browsers für Entwickler. Sie ersetzt die bisherige Aurora-Version von Firefox und versammelt bekannte Entwicklertools unter einem Dach.

  • Firefox OS

    Javascript, HTML 5 und jede Menge Linux- und Android-Erbschaften: Das ist Firefox OS, das Smartphone-Betriebssystem, mit dem Mozilla auf den Markt der günstigen Smartphones drängt. Das Linux-Magazin hat die ersten beiden Referenz-Entwicklergeräte Keon und Peak von Geeksphone getestet.

  • Grenzen überwinden

    Qt gibt C++-Unkundigen mit der Qt Metaobject Language neuerdings eine deklarative Beschreibungssprache für Apps an die Hand. Ebenfalls neu: Das Addon Qt Mobility ergänzt die Qt-Werkzeugkiste um APIs für mobile Geräte. Hybride Apps aus QML und C++ verbinden das Beste aus beiden Welten.

     

comments powered by Disqus

Stellenmarkt

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.