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.
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.
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.
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.
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 }
Letzter Blickkontakt
In der Web-IDE von Firefox testet der Entwickler abschließend die Praxistauglichkeit der App. Sie bietet eine komplette Entwicklungsumgebung für Firefox-OS-Apps und überspielt die Apps zum Testen und Debuggen auf ein per USB verbundenes Firefox Phone oder in einen Firefox-OS-Simulator. Die elegante IDE ersetzt den hausbackenen App-Manager, braucht aber noch Feintuning. Der systemeigene Editor kann Geany noch nicht das Wasser reichen.
Die Web-IDE ist in neuen Versionen von Firefox bereits enthalten und lässt sich zum Beispiel über »Extras | Web-Entwickler« aufrufen. Der Rechner muss vor dem Start mit dem Internet verbunden sein. Abbildung 3 zeigt die Web-IDE unter Firefox 35.1 auf Ubuntu 12.04. Die Beispiel-App ist bereits über »Projects | Open Packed App« in die IDE geladen, im linken Bereich erscheint dann die Verzeichnisstruktur aus Listing 3. Sie ist interaktiv und hilft dem Entwickler dabei, Dateien und Verzeichnisse auszuwählen und zu bearbeiten.
Die Angaben zur Beispiel-App rechts daneben liest die Web-IDE aus dem Manifest (Listing 4). Das grüne Feld mit der Aufschrift »valid« links oben und am rechten Bildrand signalisiert die Gültigkeit des Manifests.
Wer gerade kein Firefox Phone oder anderes Firefox-OS-Gerät zur Hand hat, testet die Praxistauglichkeit seiner App mit Hilfe des Simulators, der sich unter anderem auf der Heft-DVD befindet. Ihn installiert der Entwickler aus der Web-IDE heraus als Firefox-Plugin nach, indem er »Select Runtime | Install Simulator« auswählt und so in die Plugin-Verwaltung gelangt. Hier installiert er per Knopfdruck die gewünschte Version des Simulators (Abbildung 4).
Nach der Installation startet er den Simulator über »Select Runtime« im Hauptfenster der Web-IDE. Will der nicht, helfen eventuell die Workarounds im Kasten “Troubleshooting”. War der Start erfolgreich, zeigt der Simulator die Desktopansicht von Firefox OS (Abbildung 5).
Troubleshooting
Damit der Einsatz des Simulators nicht am X-Server scheitert, startet Firefox über die Befehlsfolge »xhost + && firefox« aus der Shell. Dank »xhost +« dürfen unmittelbar vor dem Start von Firefox auch alle nicht autorisierten Fenster den X-Server benutzen.
Unter Virtualbox kann der Einsatz des Simulators an dem Modul »vboxvideo« scheitern. Es lässt sich aber vorübergehend ruhigstellen, indem der Admin die Gasterweiterungen deinstalliert oder die Datei »vboxvideo.ko« temporär umbenennt, um dann Ubuntu neu zu starten. Das Umbenennen erledigt, abhängig von der Kernelversion, der Befehl »sudo mv /lib/modules/Kernelversion/misc/vboxvideo.ko /lib/modules/Kernelversion/misc/vboxvideo.ko.renamed« .
Im nächsten Schritt installiert und startet der Entwickler die zuvor ausgewählte App durch Klick auf den triangelförmigen Play-Knopf im Hauptfenster der Web-IDE. Abbildung 6 zeigt die App Firemerl im Simulator. Mit ein paar Klicks überzeugt sich der Entwickler vom fehlerfreien Betrieb seiner App und bessert eventuell nach.
Im Test klangen die ausgegebenen Töne unterschiedlich laut. Die Lautstärke nahm mit der Tonhöhe rapide ab, das tiefe E war nur schwer hörbar, was der Entwickler korrigierte, um die App erneut in den Simulator zu schicken. Übrigens: In derselben Leiste der Web-IDE startet der Knopf ganz rechts ein Analysewerkzeug, mit dessen Hilfe ein Tester die App zur Laufzeit untersucht.
Die Lücke schließen
Nach dem erfolgreichen Praxistest gilt es nun, die fertige Beispiel-App im Internet zu verteilen. Der Shellbefehl »cd src && zip -r package.zip ./« erstellt ein Zip-Archiv der App. Anschließend kann der Entwickler sie über den App-Store von Firefox OS [6] oder über die eigene Webseite [7] verbreiten. Wenn die App auch unter Chromium OS laufen soll, muss er eigentlich nur das Manifest austauschen [8].
Generell bieten alle mobilen Plattformen einen HTML-5-fähigen Browser an, insofern ist die Beispiel-App universell verwendbar. Wer Firemerl als native App unter Android, I-OS oder Ubuntu einsetzen möchte, dem hilft eine Vielzahl von Tools. So bietet der App-Store von Firefox an, die App mit Hilfe des Dienstes APK Factory Service [9], der sich auch auf der Heft-DVD befindet, in eine Android-App zu verwandeln.
Einen universelleren Ansatz bietet das Open-Source-Framework Apache Cordova [10], das weitgehend kompatibel mit Adobes Phone Gap ist. Das Framework unter Apache-Lizenz bietet eine einheitliche Kommandozeilen-Schnittstelle, um HTML-5-basierte, native Apps für eine Vielzahl mobiler Plattformen zu erzeugen, darunter Amazon Fire OS, Android, Blackberry 10, Firefox OS, I-OS, Ubuntu, Windows Phone 8, Windows und Tizen. Jedoch muss ein Entwickler zuvor jeweils die Entwicklungsumgebung des Herstellers installieren. Einschränkend kommt hinzu, dass beispielsweise Ubuntu 12.04 keine Apps für I-OS generieren kann. Im Netz stoßen Interessierte auf weitere IDEs, die zum größten Teil aber einen kommerziellem Hintergrund haben.
Fazit
Firefox OS bietet Webentwicklern die Möglichkeit, ihr Talent und Können in der App-Entwicklung zu zeigen, ohne dass sie dazu den steinigen Pfad der App-Programmierung für Android oder I-OS betreten müssen. Die Firefox-OS-Anwendungen können dabei auf mehr Schnittstellen als gewöhnliche Webapps zugreifen.
Das Firefox-Betriebssystem bietet neben den aus den Browsern bekannten Webprogrammierschnittstellen wie Webstorage, Indexed-DB, Geoloaction-API zusätzlich systemeigene Programmierschnittstellen [11]. Zu diesen gehören unter anderem FM Radio, Alarm, Moz-Notification oder TCP Socket, die über die Sandbox des Browsers hinaus mit dem System wechselwirken. Die fertigen Apps lassen sich zudem über Apaches Cordova-Plattform und andere Helferlein auf eine Vielzahl zusätzlicher Plattformen übertragen. Bleibt zu hoffen, dass sich die Firefox-OS-Apps künftig noch universeller verbreiten und irgendwann so gängig werden, wie es Webseiten heute sind.
Infos
- Apps für Firefox OS bauen: https://developer.mozilla.org/en-US/Apps/Build/Building_apps_for_Firefox_OS
- Der freie Allround-Editor Geany: http://www.geany.org
- Jquery: https://jquery.com
- Webapps-Spezifikation: http://mozilla.github.io/webapps-spec/
- App-Permissions: https://developer.mozilla.org/en-US/Apps/Build/App_permissions
- Marktplatz von Firefox OS: https://marketplace.firefox.com
- Apps selbst anbieten: https://developer.mozilla.org/en-US/Marketplace/Options/Self_publishing
- Firefox-Apps auf Chromium OS: https://developer.chrome.com/apps/first_app
- APK Factory Service: https://github.com/mozilla/apk-factory-service
- Apaches App-Framework Cordova: http://cordova.apache.org
- Mozillas Programmierschnittstellen: https://developer.mozilla.org/en-US/Apps/Reference












