Geschätzte Zeit zum Lesen: circa 4 Minuten

Was ist Apache Cardova ? Was ist Phonegap ?

Apache Cardova ist die Engine, das Framework auf das Phonegap aufbaut. Es existieren beide Tools als Basis für die Entwicklung.

Ein wesentlicher Unterschied zwischen den beiden, ist das Phonegap die Möglichkeit bietet über einen Webservice die Apps für die entsprechenden Ziel Plattformen quasi in der Cloud zu erstellen. Der Vorteil des Build Services dabei ist, dass es nicht von nöten ist, alle SDK Versionen für die verschiedenen Plattformen (Android, IOS, Windows Phone, Blackberry, Symbian usw. ) lokal zu haben.

Für die exemplarische Darstellung werden wir im weiteren Verlauf auf Phonegap setzen und eine kleine Beispiel App entwickeln die den Accelerometer Sensor des jeweiligen Gerätes auswertet und einen Ball bewegt.

Dank NodeJS und dessen package Manager npm, ist die Installation von PhoneGap kein Hexenwerk.

sudo npm install -g phonegap

Vorraussetzungen für das erstellen einer Android App via Phonegap sind - JAVA - ANT - und natürlich das Android SDK welches sich im Pfad befinden muss

Falls nicht alle Vorrausetzungen efüllt sind wird das folgenden definitiv nicht funktionieren,

phonegap create my-app
cd my-app
phonegap run android

Sind alle abhängigkeiten erfüllt wird phonegap die App Erstellen und zuerst versuchen die App auf einem angeschlossenem Android Phone zu installieren und zu starten. Falls kein Android Gerät angeschlossen ist, wird über den AVD (Android Virtual Device) Manager versucht ein Emulator zu starten und die App auf diesem auszuführen.

Soweit so gut, um nun einzelne Features die ein Mobile Gerät mit sich bringt zu nutzen, müssen einzelne Plugins geladen werden. Das geschieht wieder über das phonegap Kommmando.

phonegap local plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-device-motion.git

Jetzt sind wir in der Lage den Beschleunigungssensor auszulesen und seine Werte die er uns für die 3 Achsen (X,Y,Z) liefert zu interpretieren. Generell gilt der Beschleunigungssensor liefert uns keine Absoluten Lage Werte, stattdesen liefert er uns Werte die die Abweichung zum vorherigen Wert dartsellen.

Der Acc kann über die Phonegap API ausgelesen werden. Es existieren drei wichtige Methoden.

  • accelerometer.getCurrentAcceleration (liest einmalig die Werte aus)
  • accelerometer.watchAcceleration (liefert kontinuierlich Werte abhängig von dem Übergebenen Intervall)
  • accelerometer.clearWatch (stopt die Überwachung der Werte, welche durch accelerometer.watchAcceleration begonnen wurde)

API Methode navigator.accelerometer.watchAcceleration

navigator.accelerometer.watchAcceleration(onSuccess, onError, { frequency: 16});

Hier das Vollständige Beispiel für das Auslesen der Werte und und das setzen des Balles.

var stage = (function(){
    var self = {}, debgSelector = 'dbg', dbgElement = null,
    accValue = {
             AccX: 0,
             AccY: 0,
             AccZ: 0,
             TimeStamp: 0
          };

    self.init = function(){
        dbgElement = document.getElementById(debgSelector);
    }

    self.updateAccValue = function(topics, data){
        accValue = data;
        updateDebugValue();
        updateBallPosition();
    }

    var updateDebugValue = function updateDebugValue(){
        dbgElement.innerText = 'AccX :' + accValue.AccX + '\n'  +
                               'AccY :' + accValue.AccY + '\n'  +
                               'AccZ :' + accValue.AccZ + '\n'  +
                               'TimeStamp :' + accValue.TimeStamp + '\n';
    }

    var updateBallPosition = function updateBallPosition(){
        var ball = $('#ball');
        var field = $('#stage');

        var objPosition = ball.position();
        var leftBoundary = 0;
        var topBoundary = 0;
        var rightBoundary = field.width() - ball.width() - 2;
        var bottomBoundary = field.height() - ball.height() -2;
        var stepValue = 10;

        if( accValue.AccX < 0 && objPosition.left <= rightBoundary ) {
            ball.css({
                left:'+=' + (stepValue * Math.abs(accValue.AccX))
            });
        } else if( accValue.AccX > 0 && objPosition.left > leftBoundary ) {
            ball.css({
                left:'-=' + (stepValue * Math.abs(accValue.AccX))
            });
        }
        if( accValue.AccY < 0 && objPosition.top > topBoundary ) {
            ball.css({
                top:'-=' + (stepValue * Math.abs(accValue.AccY))
            });
        } else if(accValue.AccY > 0 && objPosition.top <= bottomBoundary ) {
            ball.css({
                top:'+=' + (stepValue * Math.abs(accValue.AccY))
            });
        }
    }

    return self;
})()


var acc = (function(pubsub){
    var self = {}, watchUpdateIntervall = 16;

    self.init = function(){
        watchAcc();
    }

    var watchAcc = function watchAcc(){
        navigator.accelerometer.watchAcceleration(onSuccess, onError, { frequency: watchUpdateIntervall});
        //setInterval(onSuccessdbg,500);
    }

    var onSuccess = function onSuccess(acceleration) {
        pubsub.publish("newAcc", {
            AccX: acceleration.x,
            AccY: acceleration.y,
            AccZ: acceleration.z,
            TimeStamp: acceleration.timestamp
          })
    };

    var onError = function onError() {
        pubsub.publish("newAcc", {
             AccX: 0,
             AccY: 0,
             AccZ: 0,
             TimeStamp: 0
          })
    };

    return self;

})(pubsub)

var gameManager = (function(acc, stage, pubsub){
    var self = {};

    self.init = function(){
        stage.init();
        acc.init();
        var subscription = pubsub.subscribe( "newAcc", stage.updateAccValue );
    }

    return self;
})(acc, stage, pubsub)

Das Acc Modul liest kontinuierlich die Werte aus und gibt diese über den Channel “newACC” an das “Publisher Subscriber” Modul welches das Event-Handling für uns übernimmt. Die Methoden welche bei dem Abonieren dieses Channels hinterlegt wurden werden mit den neuen Werten des Acc’s als Argument aufgerufen. In unserem Fall, ist das die Methode updateAccValue aus dem StageModule. Diese ändert nun alle Sichtbaren Objecte, welche von dem Beschleunigungssensor abhängen, in unserem Fall die Ball Position. Damit das ganze auch ein wenig an Schwung bekommmt multiplizieren wir den Absoluten Wert des Accs mit unserer Schrittweite. Ein paar css Anweisungen und ein paar Bilder geben dem Ganzen ein mehr Form und Gestalt.

Alt text

Soweit so gut! Zu diesem Zeitpunkt haben wir eine kleine App, die abhängig von der Winkelbeschleunigung auf den Achsen X und Y, einen Ball auf einem Feld bewegt.

Link zur APK: HelloWorld-debug.apk

Link zum Projekt: phonegap-android-example.zip