map.apps Apps als native (hybride) Apps auf Android-, iOS- oder Windows-Geräten zu nutzen ist einfach und dank einheitlicher Code-Basis sehr effizient. Der nächste Schritt, um diese einfache Portierung ansprechend in Wert zu setzen, ist es, die von den Geräten exklusiv bereitgestellten Funktionen in map.apps zu nutzen.
Im einzelnen besteht die Serie aus folgenden Artikeln:
- Native Apps 1 - Export und Konvertierung von map.apps Apps zur Bereitstellung als native App
- Native Apps 2 - Vom Sensor in die App - Nutzung nativer Gerätefunktionen in map.apps (dieser Artikel)
- Native Apps 3 - Mit map.apps in den App Store - Die Veröffentlichung nativer Apps (folgt in Kürze)
Einleitung
In Teil I dieser Artikelserie wurde beschrieben, wie auf einfache Art und Weise aus einer map.apps App eine native (hybride) App für verschiedene Plattformen erstellt werden kann. Schlüssel zu diesem Workflow ist die Nutzung von Apache Cordova (http://cordova.apache.org/). Über den map.apps Manager wird eine Standalone-App exportiert, welche aus dem Dateisystem heraus gestartet werden kann. Über Github kann ein Rahmen bezogen werden (https://github.com/conterra/mapapps-phonegap-build-frame) welcher die grundlegende Struktur für die Weiterverarbeitung bereitstellt und über den Online-Dienst PhoneGap Build (https://build.phonegap.com) können daraus kostengünstig native Apps erstellt werden.
Im vorliegenden Artikel soll nun beschrieben werden, wie es über Cordova möglich ist, native Gerätefunktionen anzusprechen und in map.apps zu Nutzen.
Was sind native Gerätefunktionen?
Bei nativen Gerätefunktionen handelt es sich um Funktionen, die von dem Gerät, auf dem eine App installiert ist, bereitgestellt werden, beispielsweise der Zugriff auf bestimmte Sensordaten. Dazu zählen unter anderem der Batteriestatus, die Qualität und Quelle des Internetzugriffs, die Kamera, Orientierung oder einfach das GPS zur Positionsbestimmung.
Einige dieser Funktionen, wie beispielsweise der Zugriff auf die Position des Nutzers, sind in modernen Browsern direkt über bestimmte Schnittstellen verfügbar (z.B. https://developer.mozilla.org/en-US/docs/Web/API/Geolocation), ganz unabhängig davon, ob das ausführende System (also z.B. der Desktop-Browser) die Position aus einem GPS-Empfänger zieht, oder beispielsweise über das Netzwerk ermittelt.
Andere Funktionen jedoch, wie beispielsweise der Zugriff auf den Vibrationsalarm sind ausschließlich mobilen Endgeräten vorbehalten. Um diese auch für eine normale Webanwendung wie map.apps verfügbar zu machen, stellt Cordova über sogenannte Plugins Schnittstellen bereit, welche im JavaScript-Code genutzt werden können, und welche nach dem Build mit Cordova und dem Installieren auf dem Gerät reale Werte der Sensoren des Smartphones oder Tablets liefern.
Ein Kompass für map.apps
Cordova Plugins
Am Beispiel der Device Orientation soll im Folgenden gezeigt werden, wie in map.apps mit Hilfe von Cordova ein Kompass gebaut werden kann, um die Ausrichtung des Smartphones nach Norden darzustellen.
Zunächst ist es notwendig, ein Cordova Plugin für die gewünschte Funktionalität zu finden. Unter http://cordova.apache.org/docs/en/latest/plugin_ref/spec.html finden sich alle offiziell unterstützten Cordova Core Plugins. Zudem ist es möglich, eigene Plugins zu schreiben und per npm zu veröffentlichen bzw. bestehende Plugins von npm zu nutzen. Für den Kompass wird das Plugin "Device Orientation" genutzt, dessen Dokumentation hier gefunden werden kann: http://cordova.apache.org/docs/en/6.x/reference/cordova-plugin-device-orientation/index.html
Ist das passende Plugin gefunden, wird es der Datei „config.xml“ im PhoneGap-Rahmen hinzugefügt, damit die Funktionen des Plugins nach dem Build zur Verfügung stehen. Im veröffentlichten Rahmen auf Github sind schon einige Plugins einkonfiguriert und andere vorbereitet: https://github.com/conterra/mapapps-phonegap-build-frame/blob/master/config.xml
Best Practices im Umgang mir den Cordova Schnittstellen
Die über die Plugins bereitgestellten Schnittstellen sind, wie bereits erwähnt, nach dem Build über Cordova / PhoneGap verfügbar, häufig jedoch erst, nachdem ein von Cordova bereitgestelltes „deviceready“ Event beim Appstart geworfen wird.
Dies bedeutet für die Entwicklung eines map.apps Bundles, dass die Schnittstellen zwar ohne Einschränkung genutzt werden können, für die Nutzung im „normalen“ Modus im Browser aber dringend Checks eingebaut werden müssen, ob die aufgerufenen Schnittstellen vorhanden sind. Ansonsten funktioniert das Bundle wunderbar in der nativen App, im Browser werden jedoch Fehler (Null-Pointer-Exceptions) ausgegeben.
Auch führt dies dazu, dass quasi „blind“ programmiert werden muss, da sich das konkrete Verhalten erst nach dem Build mit Cordova auf dem Gerät einstellt, während viele Funktionen in der Desktop-Variante nicht verfügbar sind. Ein Ausweg ist das Mocken / Simulieren der Schnittstellen in Unit-Tests. Zumindest für die offiziellen Plugins von Cordova sind die verwendeten Schnittstellen gut dokumentiert, sodass sich die Entwicklung meist nicht als allzu schwierig darstellt.
Aus der dokumentierten Struktur der über die Sensoren ermittelten Daten / Objekte lässt sich ableiten, was von den einzelnen Methoden der Plugins zurück gegeben wird. Bei konsequenter Einhaltung von Programmierpatterns wie MVVM und Nutzung von Oberflächenwidgets welche sich durch Veränderung von Daten in einem sogenannten Model updaten / verändern, ist es dann möglich, eben jenes Model während der Entwicklung nicht durch reale Werte der Plugin-Schnittstelle zu füllen, sondern z.B. durch randomisierte Werte, welcher der benötigten Struktur entsprechen. So ist es möglich, auf den Sensordaten basierende Oberflächen zu bauen, ohne den Sensor verfügbar zu haben.
Bei der Entwicklung bietet sich die Modultrennung an, also den Zugriff auf die Plugin-Schnittstelle in einem extra Bundle zu verpacken, welches vom eigentlichen Widget-Bundle genutzt wird. In diesem geräteabhängigen Bundle können dann, je nach Verfügbarkeit, entweder die realen Daten des Gerätesensors oder die simulierten Daten zurückgegeben werden. Für das konsumierende Widget sieht die Schnittstelle in beiden Fällen gleich aus.
Prototypischer Entwicklungsworkflow
So viel zum kleinen theoretischen Exkurs über Best Practices im Umgang mir den Cordova Schnittstellen. Doch wie sieht ein prototypischer Entwicklungsworkflow aus? Auf Github unter https://github.com/conterra/mapapps-compass ist die angesprochene Kompass-App veröffentlicht.
Dabei handelt es sich um ein klassisches Entwicklungsprojekt, welches die normale map.apps Bundle-Entwicklung ermöglicht. Bereitgestellt werden hier drei Bundles: ein Device-Service, welcher die genannten Zugriffe auf die über Cordova bereitgestellten Schnittstellen kapselt und zwei konsumierende Bundles, welche sich an die oben genannten Patterns halten. Zum einen der eigentliche Kompass, welcher in klassischen Desktop-Szenarien, in denen kein Zugriff auf die Orientierung besteht, einen „Random“-Button bereitstellt, um das zugrundeliegende Model mit zufälligen Daten zu füllen. Zum anderen einen sog. POI-Finder, welcher die Device-Orientation mit der Geolocation kombiniert, um Entfernung und Richtung zu allen Niederlassungen der Esri Deutschland Gruppe abhängig der eigenen Position darzustellen. Letzteres ermöglicht es sogar, die Position unabhängig vom Gerät zu ermitteln, da, wie erwähnt, die Geolocation API auch auf dem Desktop funktioniert und Cordova dieselben Schnittstellen bereitstellt.
Das Entwicklungsprojekt ist als Remote-Projekt gegen eine entfernte map.apps Instanz konfiguriert. Ist die Entwicklung der Bundles in diesem abgeschlossen, können sie über das Maven Goal „mvn clean install -P compress,release“ gebaut werden. Anschließend müssen die Bundles in eine map.apps Installation über den Manager hochgeladen werden. In diesem wird eine App angelegt, welche die Bundles verwendet. Empfohlen wird, das dem Entwicklungsprojekt beiliegende App-Template zu benutzen. In diesem ist beispielsweise das Bundle „map-preload-2D“ integriert, welches bestimmte Esri-Ressourcen bündelt um die Performance zu verbessern.
Erstellung der fertigen App
Die nun so vorbereitete App sollte im Browser getestet werden. Über den Manager kann sie nun für die Weiterverarbeitung per PhoneGap Build exportiert werden. Wie genau ist in Teil I dieser Serie beschrieben.
Wie schon erwähnt, sollte nun bei der Weiterverarbeitung darauf geachtet werden, dass das entsprechende Cordova Plugin in der Datei „config.xml“ aktiviert ist. Die mit dem Rahmen verheiratete Standalone-App kann dann in PhoneGap Build hochgeladen und auf den entsprechenden Geräten installiert werden. Im Idealfall werden nun die realen Daten des Orientierungssensors zur Befüllung des Models genutzt und der Kompass dreht sich entsprechend der Blickrichtung.
Zusammenfassung
In der folgenden Liste sind die nötigen Schritte zur Nutzung nativer Gerätefunktionen in map.apps zusammengefasst:
- Bundle entwickeln, welches die gewünschte Funktion entsprechend der Schnittstellendokumentation des Cordova Plugins anspricht.
- Dabei darauf achten, dass die Funktion im Desktop-Browser ggf. simuliert werden muss.
- Das Bundle via „mvn clean install -P compress,release“ bauen.
- Das fertige Bundle in eine map.apps Instanz hochladen.
- Eine App erstellen, welche das Bundle nutzt.
- Die App über den Manager für die Weiterverarbeitung als native App exportieren.
- Den PhoneGap-Rahmen klonen: https://github.com/conterra/mapapps-phonegap-build-frame.
- Die exportierte App im Ordner „www“ ablegen.
- In der Datei „config.xml“ darauf achten, dass das verwendete Cordova Plugin aktiviert ist.
- „www“ und „config.xml“ zippen.
- Das Archiv in PhoneGap Build hochladen.
- App installieren und native Funktionen nutzen.
Abschließend eine Sammlung von relevanten Links:
- Apache Cordova: http://cordova.apache.org
- Config.xml Referenz: http://cordova.apache.org/docs/en/latest/config_ref/index.html
- PhoneGap Build: https://build.phonegap.com
- map.apps Rahmen für PhoneGap: https://github.com/conterra/mapapps-phonegap-build-frame
- Kompass Beispiel auf Github: https://github.com/conterra/mapapps-compass