Geek. Coder. Gamer. Bayern Munich Fan.
Visit my blog stream http://writeline.io
My Name is Dariusz Parys
I'm also known as Writeline
I'm a Technical Evangelist @ Microsoft Germany and you can follow me on Twitter or visit my blog stream.
Ember.js ist ein MVC Framework um Single Page Applications kurz SPA zu realisieren. In einem kleinen Proof of Concept habe ich eine Anbindung an die Windows Azure Mobile Services (WAMS) getestet. Zur Anbindung habe ich nicht Ember-Data genutzt sondern den Proxy Code von WAMS.
Es gibt viele JavaScript basierte Frameworks um Single Page Applications zu realisieren. Die bekanntesten darunter sind Backbone, Knockout, Angular und Ember. Gefühlt gibt es mit Sicherheit noch weitere hunderte von solchen Bibliotheken und Frameworks, aber diese vier sind letztlich mir im Gedächtnis geblieben. Single Page Applications geben mir...
Hier geht es zum Post - I Like Ember.js
Heutzutage werden Websites mit den unterschiedlichsten Endgeräten besucht. Vom traditionellen Desktop PC über Laptops, Netbooks, MacBooks bis hin zu iPhones, Windows Phones und Fernsehgeräten samt Spielekonsole. Wie gelingt es aber, dass auch jeder Besucher die Website auf seinen Bildschirm angepasst präsentiert bekommt? Dieser Artikel gibt eine Einführung in Responsive Webdesign mit dem CSS3 Grid Module.
Die meisten Websites haben ein Problem mit der Vielzahl an Endgeräten. Das Problem liegt im Design des Layouts begründet. Lange Zeit war es Mode, ein fixed Layout zu benutzen. Meist hat man hierzu im CSS folgendes definiert:
.page { margin: 0px auto; width: 980px;}
Das funktioniert super, solange die Mindestbreite des Browsers 980 Pixeln entspricht. Als zweites Beispiel nehmen wir ein Blog. Das Beispiel-Blog verwendet WordPress und das Theme hat folgende Layout-Definition
#wrapper { width: 960px; margin: 30px auto; background: #fff; border: 1px dotted #000;}#main { width:610px; padding: 2em 30px; }.col-full { width: 960px; margin:0 auto; }#main.fullwidth, .layout-full #main { width: 900px; margin:0 auto;}#sidebar { width:290px; background: #f2f2f2; }#sidebar .secondary { width:140px; }.entry img { max-width:610px; }
Smartphones haben in der Regel keine 960 Pixel breiten Displays. Sie bedienen sich aus diesem Grund für die Anzeige eines einfachen Tricks. Websites werden in die Smartphone-Auflösung reinskaliert. Besucher erhalten in der Regel die identische Seite wie auf einem Desktop angezeigt, wenn keine spezielle mobile Version der Seite vorliegt. Auf einem Lumia 800 wird die Seite auf eine Größe von 800 x 480 Pixeln heruntergerechnet.
Das funktioniert eigentlich ganz gut, man muss lediglich für die Lesbarkeit in den Text zoomen. Besser wäre jedoch eine Version der Website, die sich optimal auf diesem Display darstellt. Und genau hier kommt Responsive Webdesign ins Spiel.
Eine vereinfachte Definition von Responsive Webdesign lautet:
Responsive Webdesign ist die Anpassbarkeit einer Webseite auf verschiedene Formfaktoren. Dabei bleiben alle wesentlichen Elemente visuell und funktional erhalten.
Testen wir mal die Responsiveness des Beispiel-Blog. Im Web existieren verschiedene Online Tools, um Responsive Webdesign zu testen. Eines davon ist von Matt Kersley. Sein Tool für das Responsive-Webdesign-Testing zeigt die angegebene URL in verschiedenen Auflösungen.
Das Tool emuliert keine Endgeräte, sondern dient vielmehr dazu, schnell ein Gefühl dafür zu bekommen wie sich die eigene Webseite in verschiedenen Screen-Größen verhält. Das Resultat für das Blog: Absolut nicht responsive.
Beispielhaft soll eine Textbasierte Seite mit Hilfe von ein paar CSS Hilfsmitteln „Responsive“ gemacht werden. Dazu nimmt man das „article“-Elemente mit folgenden Inhalt:
<article> <h2>Überschrift</h2> <p>Inhalt...</p><article>
Mit einigen Lorem Ipsum Texten und einer Hintergrundgrafik die oben rechts positioniert ist sieht die Website wie folgt aus:
Wenn man mit neuen CSS-Techniken arbeitet, kommt man noch nicht um Vendor-Prefixe herum. Damit spricht man speziell eine noch nicht final standardisierte Implementierung eines Browsers an. Damit das Beispiel nicht zu umfangreich wird, berücksichtigt man vorerst lediglich den Internet Explorer 10 und Webkit-fähige Browser wie Chrome und Safari.
Fangen wir mit der Positionierung des Inhaltes an. Hierfür nehmen wir ein GridLayout. Das Gridlayout ermöglicht eine Aufteilung eines Elements in Spalten und Zeilen. Neben den üblichen fixen Positionierungsmöglichkeiten wie Pixeln gibt es auch die „fractions“-Einheit. Diese deklariert die Anteile eines verfügbaren Platzes. Der Browser rechnet dementsprechend in Pixel um. Das Layout für das Beispiel soll etwas links versetzt angezeigt werden, mit mehr Platz nach rechts, wie unten im Schaubild nachgestellt.
Die GridLayout-Definition für das „body“-Element für die Seiteninhalte sieht dann in CSS so aus:
display: -ms-grid;-ms-grid-columns: 1fr 5fr 2fr;-ms-grid-rows: 1fr 12fr;
Die „section“ muss nun entsprechend in die richtige Zeile und Spalte platziert werden.
section { -ms-grid-row: 2; -ms-grid-column: 2;}
Hier gibt es noch keine WebKit-Implementierung der W3C Spezifikation, deshalb lediglich der -ms Prefix. Das Resultat im Browser spiegelt das angedachte Layout des Grids wider.
Neben dem traditionellen 4:3 Bildschirm Format sind heute Seitenverhältnisse von 16:10 und 16:9 angesagt. Einen breiteren Screen sollte man auch ausnutzen. Allerdings liest sich Text nicht besonders gut auf einem Breitbildschirm über dessen gesamte Breite. Hier bietet es sich an, diesen mehrspaltig darzustellen. Das ist mit Hilfe des CSS Multi-column Layout Module schnell realisiert:
article { -webkit-column-count: 3; -webkit-column-gap: normal; -webkit-column-rule-color: gray; -webkit-column-rule-style: solid; -webkit-column-rule-width: 1px; -webkit-column-width: auto; column-fill: auto; column-gap: normal; column-rule: 1px solid gray; columns: 3 auto; height: auto; overflow-x: auto; overflow-y: auto; margin-bottom: 50px;}
Der CSS-Code definiert für das „article“-Element eine dreispaltige Textverteilung, mit einer Trennlinie von einem Pixel dazwischen.
Die letzte CSS-Technik die wir verwenden sind sogenannte Media Queries . Damit kann der Webentwickler – abhängig von Abfrageparametern – Elemente unterschiedlich stylen.
Dazu wird folgende Grundsyntax verwendet:
@media [type] [and (query) | * ]
Typischerweise fragt man „width“ ,„height“ , „device-width“ , „device-height“ , „aspect-ration“ , „device-aspect-ratio“ und „orientation“ ab. Es gibt noch die Möglichkeit, Farbunterstützung und sogar die Scan-Rate des Fernsehgerätes in der Query anzugeben.
Möchte man zum Beispiel einen Style für ein iPhone deklarieren, so definiert man einfach:
@media screen and (max-device-width: 480px) { /* hier kommen die CSS Regeln rein */}
Auch die Beispielseite soll nun Media Queries erhalten. Dazu legt man nun fest, dass bei einer Mindestauflösung von 720p der Text dreispaltig angezeigt wird. In allen anderen Fällen wird der Text zweispaltig und auf Smartphones nur noch einspaltig und ohne GridLayout angezeigt. Im übrigen ist diese Spaltenaufteilung abhängig vom Display völlig willkürlich und soll nur die Möglichkeit der Anwendung von Media Queries verdeutlichen.
Hierfür definiert man zwei Media Queries:
@media screen and (max-width: 480px) { /* 1-Spaltig, kein GridLayout, 64 Pixel Grafik, Schriftgröße 100% */}@media screen and (min-width: 1280px) and (device-aspect-ratio: 16/9) { /* 3-Spaltig, GridLayout, 512 Pixel Grafik, Schriftgröße 150% */}@media screen{ /* 2-Spaltig, GridLayout, 256 Pixel Grafik, Schriftgröße 120% */}
Wir haben für die Demo nicht die Geräte-Werte abgefragt, sondern die momentane Browser-Größe. Für eine richtige Anwendung muss man hier auch die entsprechenden „device-*“-Abfragen nutzen. Zu guter letzt sei noch erwähnt, dass zusätzlich für mobile Geräte noch ein Meta Tag hinzugefügt werden sollte.
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1>
Mit dieser Meta-Anweisung wird ein Mobilgerät nicht versuchen, eine Desktop-Seite einfach herunterzuskalieren, sondern das Responsive Design kann direkt angewendet werden.
Dieser Artikel kratzt nur an der Oberfläche von Responsive Webdesign. Wer sich tiefer mit dem Thema beschäftigen möchte, dem sei das Buch Responsive Web Design empfohlen. Es behandelt ausführlich die Erstellung einer Seite nach diesen Prinzipien. Des Weiteren noch eine Alternativ-Empfehlung zum Online Testen einer Webseite namens ScreenFly .
Falls Eure Webseite noch nicht "Responsive" ist und Euch Inspiration fehlt, dann werft doch einen Blick auf die Gewinner des 10k Apart "Responsive Edition" Wettbewerbs .
Die Integration eines Videoclips auf der eigenen Webseite war bisher nur durch die Verwendung zusätzlicher Software wie Adobe Flash, Microsoft Silverlight oder anderen Plugin-Technologien möglich. Mit der Verbreitung von HTML5-fähigen Browsern hält nun das Video-Element Einzug in die Hypertext Markup Language.
Es könnte so einfach sein. Um ein Video auf der eigenen Webseite anzuzeigen, deklariert man einfach
<video src="http://meineseite.de/media/video.mp4"></video>
und öffnet die Seite mit einem modernen Browser
Ganz so leicht geht es dann aber doch nicht. Man wird nur ein schwarzes Rechteck zu Gesicht bekommen, falls der passende Video-Codec vom Browser unterstützt wird, ansonsten eine Fehlermeldung, die besagt, dass die angegebene Quelle nicht unterstützt wird.
Anwender haben dem Video-Element mehr Informationen mitzugeben, damit ein Video auf der Webseite auch abgespielt werden kann.
Das Video Element verfügt über eine Reihe von Attributen, die man angeben kann:
Ergänzt man das Beispiel von oben mit dem Attribut „controls“ werden die Standard Bedienelemente des Browsers für die Steuerung des Videos eingeblendet.
Die übrigen Attribute bewirken Folgendes:
Je nach verwendeten Browser werden unterschiedliche Video-Codecs unterstützt. Nach heutigem Stand bieten sich zur Wiedergabe von Video-Inhalten folgende Codecs an: „H.264“, „Theora“ und „WebM“. Theora und WebM sind Open-Source-Codecs, iH.264 – der mit Abstand am häufigsten genutzte Codec – ist proprietär. Dank der hohen Verbreitung an Medien in diesem Format gibt es auch viele Hardware-Player wie DVD-Player, Fernsehgeräte und Settop-Boxen, die eine direkte H.264 Unterstützung eingebaut haben.
Der Internet Explorer unterstützt H.264 und mit einer nachträglichen Installation auch WebM. Chrome hingegen unterstützt WebM und Theora, hat aber seinen H.264-Support bereits aufgekündigt. Firefox unterstützt Theora und WebM, während Safari von Haus aus H.264 unterstützt und auf iOS nur H.264 unterstützt.
Damit fallen zwangsläufig die Würfel und man sollte seine Videos in allen drei Varianten anbieten, wenn man niemanden außen vor lassen will. So könnte eine Deklaration der Quellen aussehen:
<video controls> <source src="http://meineseite.de/media/video.mp4" type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"' /> <source src="http://meineseite.de/media/video.webm" type='video/webm; codecs="vp8, vorbis"'/> <source src="http://meineseite.de/media/video.ogv" type='video/ogg; codecs="theora, vorbis"'/> </video>
Das Attribut „type“ im Element „source“ kann man weglassen, dann werden Standardwerte für das jeweilige Videoformat genommen.
Natürlich sollte man auch den Fall der Fälle einplanen: Webseiten-Besucher mit einem nicht HTML5-fähigen Browser. Hier kann man auf die Eigenschaft des Browser-Parsings zurückgreifen. Elemente, die ein Browser beim Parsen der Seite nicht erkennt, werden ignoriert. Dieses Verhalten kann man für eine Fallback-Strategie nutzen, die sich aus zwei Alternativen zusammensetzt:
Den Fallback deklariert man innerhalb des „video“-Elements. In diesem Beispiel bieten wir dem Benutzer einen Downoad-Link direkt auf das Video an.
Da das „video“-Element nun ein vollwertiges Mitglied der HTML-Familie ist, es sich auch per CSS manipulieren. Der folgende CSS Code wird auf alle „video“-Tags der Seite angewendet.
video:hover { // Vendor Prefixe für Internet Explorer und Webkit -ms-transform: translate(100px, 100px) rotate(15deg); -ms-transition: 2s; -webkit-transform: translate(100px, 100px) rotate(15deg); -webkit-transition-duration: 2s; -webkit-transition-property: all; -webkit-transition-timing-function: ease; border-radius: 150px 100px 0px 25px; }
Sobald man mit der Maus über das Video, fährt wird der CSS-Style aktiv und das Video bewegt sich mit einer „ease“-Animation um die Koordinaten 100 Pixel horizontal und 100 Pixel vertikal nach rechts, neigt sich dabei im Winkel von 15 Grad und erhält zudem noch abgerundete Ecken.
Mit nur wenig Aufwand lassen sich also erstaunliche Effekte erzeugen.
Mit JavaScript sind der Kreativität keine Grenzen mehr gesetzt. Video-Elemente lassen sich so dynamisch erstellen, steuern und auch grafisch manipulieren. Die zur Verfügung stehenden Methoden, Eigenschaften und Ereignisse kann man der W3C Spezifikationsdokumentation für das Video-Element bei HTML5 entnehmen. Zum Beispiel erstellt `document.createElement("video");` ein Video-Element:
<script> document.addEventListener( "DOMContentLoaded", function() { var video = document.createElement("video"); document.getElementById("container").appendChild(video); video.src = "http://meineseite.de/media/video.mp4"; video.controls = true; video.play(); }); </script> ... <div id="container"></div>
und die Funktion „play()“ startet es dann. Auch kann man einzelne Frames eines Videos auf einen Canvas kopieren.
// Surface ist hier der Canvas 2d Kontext surface.drawImage( videoElement, 0, 0 );
So lässt sich das Video parallel in einem anderen Bereich anzeigen, Filter angewendet werden oder eine Video-Preview-Timeline erstellen, wie sie im unteren Bild abgebildet ist.
Der Quellcode für das Beispiel befindet sich als Gist auf Github .
Videoinhalte lassen sich mit Untertiteln erweitern. Dazu definiert man ein „<track>“-Element innerhalb des Videos.
<track kind="subtitles" srclang="de" label="Deutsche Untertitel" src="de-captions.vtt" default>
Die Angabe der Quelle sollte dem Foramt Timed Text Markup Language (TTML) 1.0 oder Web Video Text Tracks entsprechen. Im Prinzip sind hier Zeitstempel mit den entsprechenden Textpassagen enthalten. Mit mehreren track-Elementen kann man Mehrsprachigkeit realisieren. Hier ein Beispiel , wie der Internet Explorer Untertitel im Video-Control zur Verfügung stellt und anzeigt.
Alle Browser haben noch eine Sache gemeinsam: Unterschiedlich aussehende Steuerelemente für das Video. So unterscheiden sich die visuellen Controls im Internet Explorer, Safari, Chrome, Firefox und Opera voneinander. Das kann zur Überlegung führen, eigene Controls zu zeichnen, um ein einheitliches Look & Feel über Webbrowser-Grenzen hinweg zu realisieren.
Doch das muss man nicht selbst machen. Hier kann man auf eine Vielzahl von HTML5-Video-Frameworks zurückgreifen, die meist weit mehr als nur das eigentliche Skinning des Players erlauben. Als Beispiel sei der LeanBack Player genannt. Neben CSS-Themes für die Optik bietet er auch ein Plugin-Modell, um zum Beispiel das Analytics-Tool Piwik zu integrieren.
Es ist gut, dass das Video-Element nun ein Bestandteil eines HTML-Dokumentes ist. Allerdings lassen sich zum derzeitigen Stand noch nicht alle Szenarien mit der Video-Integration abdecken. Video-Streaming (Smooth Streaming) lässt sich momentan nicht über den Standard bewerkstelligen, auch sind DRM-geschützte Inhalte noch nicht abspielbar. Web-Anwendungen, die auf diese technischen Aspekte angewiesen sind, werden sich nach wie vor mit Plugins wie Silverlight oder Flash behelfen müssen.
Ist man nicht auf diese speziellen Szenarien angewiesen und hat die Möglichkeit, seine Videos in mehreren Codecs anzubieten, so gibt es keinen Grund mehr, das Video-Element nicht einzusetzen. Nie war es einfacher, Videos einzubinden, zu stylen und zu manipulieren.
Mit HTML5 hält das Canvas-Element Einzug in die Webentwicklung. Es gibt einem die Möglichkeit auf der Webseite, auf der es verwendet wird, zu zeichnen und somit von einfachem Text über Bewegtbilder bis zu kompletten Spielen alles direkt in HTML darzustellen – ohne die Verwendung von zusätzlichen Plugins wie Silverlight oder Flash. Dieser Artikel ist eine kurze Einführung in die Möglichkeiten und Nutzung des Canvas-Elements.
Das Canvas Element ist einfach deklariert
<canvas id="meinbild" width="400" height="400"> Dieser Browser unterstützt das Canvas Element nicht! </canvas>
und wird wie alle HTML5-Elemente von Browsern, die diese nicht verstehen, einfach ignoriert. In diesem Fall wird der Inhalt zwischen den Tag-Elementen angezeigt. Doch so richtig anfangen kann man mit dem Element erst etwas, wenn man es mittels JavaScript manipuliert.
Um mit dem Canvas zu arbeiten, muss man den Modus bestimmen, in dem man zeichnen möchte. Momentan ist im HTML5-Standard nur ein 2D-Modus spezifiziert.
var canvas = document.getElementById('meinbild'); var surface = canvas.getContext('2d');
Durch den Code hat man nun Zugriff auf den Canvas Context. Auf diesen kann man mit Hilfe diverser APIs zeichnen und der Webseite Leben einhauchen. Manipuliert werden direkt die Pixel der Fläche, die man mittels Canvas deklariert hat. Im vorigen Beispiel ist dies eine Fläche von 400 x 400 Pixeln die man direkt ansprechen kann. Die Entwickler-Spezifikation vom W3C zeigt die Details des 2D Contexts für das Canvas Element. Eine weitere gute Zusammenstellung der Funktionen findet man im Cheat Sheet .
Das Prinzip zum Arbeiten mit dem Canvas ist immer das gleiche: Man setzt die Rahmenparameter und zeichnet dann Text, Linien oder Grafiken. Der Canvas verhält sich dabei genauso wie eine Leinwand. Gemaltes bleibt bestehen bis man es überschreibt. Im Prinzip wie bei einem Ölgemälde, das man immer wieder überpinseln kann.
Um Text zu zeichnen, setzt man zuerst Farbe, Schrift sowie Größe und wählt eine entsprechende Funktion zum Zeichnen.
surface.fillText( "HTML5", 0, 0 );
Der vorangehende Code zeichnet den Text "HTML5" mit den Standardeinstellungen an der Position 0,0, also in der linken oberen Ecke. Allerdings wird man sich wundern, dass kein Text zu sehen ist. Das liegt daran, dass der Text auf der y-Achse positioniert ist. Man müsste also noch 10 Pixel nach unten gehen, um den Text zu sehen. Alternativ kann man auch die Eigenschaft textBaseline umstellen.
surface.textBaseline = "hanging"; surface.fillText( "HTML5", 0, 0 );
Der Text wird dann dargestellt, wie man es erwarten würde:
Richtig schön ist der Text allerdings noch nicht. Man kann den Text aber beispielsweise mit ein wenig Schatten und einer anderen Schriftart auf hübschen:
surface.textBaseline = "hanging"; surface.font = "20pt Helvetica"; surface.shadowBlur = 10; surface.fillStyle = "red"; surface.fillText( "HTML5", 0, 0 );
Schon hat man einen netten Schriftzug:
Statt einer beliebigen Farbe kann man zum Füllen von Texten und Flächen auch Farbverläufe und Bildmuster verwenden. Zum Beispiel definiert man einen radialen Farbverlauf mit der Funktion createRadialGradient und definiert verschiedene Farbpunkte mit der Methode addColorStop auf diesen Verlauf:
var gradient = surface.createRadialGradient( 150, 100, 20, 150, 50, 200); gradient.addColorStop( 0, "white" ); gradient.addColorStop( 0.5, "yellow"); gradient.addColorStop( 1, "lightblue" ); surface.fillStyle = gradient; surface.fillRect(0,0,400,400);
Mit einfachen Mitteln hat man eine Sonne, die am blauen Himmel leuchtet.
Bilder lassen sich auch auf einen Canvas anwenden. Ein Image-Element als Quelle kann direkt auf den Canvas gezeichnet werden. Der folgende Code kopiert eine Grafik eines Image-Elements in den Canvas:
var image = document.getElementById("myImage"); surface.drawImage( image, 0, 0 );
Die Grafik wird in diesem Fall eins zu eins kopiert: Hat der Canvas zum Beispiel eine Größe von 400 x 400 Pixeln und die Grafik ist deutlich größer, sieht man nur die 400 x 400 Pixel. Der Rest wäre dann abgeschnitten.
Interessante Effekte lassen sich mit der Komposition des Canvas erstellen. Dabei kann man definieren, wie sich die nächsten Zeichen-Operationen verhalten. Der Standard ist source-over, eine Zeichen-Operation überschreibt die vorherige. Ändert man das Ganze auf destination-atop so lässt sich mit dem weichgezeichneten Schatten ein Stanz-Effekt erzeugen:
surface.drawImage( image, 0, 0, surface.width, surface.height ); surface.globalCompositeOperation = "destination-atop"; surface.shadowOffsetX = 2.0; surface.shadowOffsetY = 2.0; surface.shadowBlur = 10; surface.shadowColor = "Black"; surface.fillText( "HTML5!", surface.width / 2, surface.height / 2 );
Das Ergebnis ist der folgende Stanz-Effekt:
Dieser Effekt steht in einem jQuery Plugin auf Github zur Verfügung.
Mit Hilfe von Timer-Objekten lassen sich auch komplette Spiele realisieren. Die Grundlagen sind einfach. Man benötigt eine Game Loop, die immer wieder durchlaufen wird:
window.requestAnimationFrame( function() { updateModel(); drawSurface(); });
In der Funktion updateModel() wird letztlich das Spielmodell berechnet und auf Aktionen reagiert, die der Spieler tätigt. In der Funktion drawSurface() wird das aktualisierte Spielmodell auf den Canvas gezeichnet. Durch die Verwendung von requestAnimationFrame aktualisiert der Browser mit den höchstmöglichen Bildwiederholraten, die das System in diesem Moment zur Verfügung stellt.
Bitte benutzt ab sofort requestAnimationFrame und nicht mehr setInterval
Ein Beispiel für ein Canvas-basiertes Spiel ist Cut the Rope. Dieses ist seit kurzem in einer HTML5-Version erschienen.
Dass selbst richtige Spiele mittlerweile auf Basis von HTML5 erscheinen, ist nicht nur der Popularität von JavaScript zu verdanken, sondern der Tatsache, dass moderne Browser die Hardwarefähigkeiten des lokalen Rechners voll ausnutzen und beispielsweise den Canvas mittels GPU beschleunigen. Ein Spiel mit 60 Frames pro Sekunde ist somit kein Problem mehr und lässt den Webentwickler in ungeahnte Sphären vordringen. Wer sehen möchte, was sein Browser auf der Hardware leistet, kann sich eine entsprechende Tech-Demo anschauen.
Mit dem Canvas Element ergeben sich Möglichkeiten, die bisher Flash oder Silverlight vorbehalten waren. Ob Typografie, Bilder, Videoeffekte oder Spiele – der Canvas ist die Leinwand mit der man tolle Sachen erstellen kann. Der künstlerischen Freiheit sind keine Grenzen gesetzt.
Hast Du schon mal geschaut wie Deine Webseite unter Windows 8 im Internet Explorer im Snapped View aussieht? Vermutlich so ähnlich wie dieser Screenshot:
In diesem Fall ist es mein Stream Blog http://writeline.io der einfach auf die 320 Pixel runterskaliert wird. Dieses Blog unterstützt Responsive Design und könnte sich doch genauso darstellen wie auf einem Mobiltelefon, doch das passiert nicht. Der ein oder andere mag aus der mobilen Webentwicklung bereits das Viewport Metatag kennen.
<meta name="viewport" content="width=device-width">
Warum ist das so? Nun, der Internet Explorer setzt auf Standards. Und es gibt einen Standard der die Viewport Definition in CSS zulässt: Die W3C @viewport CSS Regel. In Kombination mit CSS Media Queries lassen sich sowohl Snapped als auch der Portrait Modus abfragen. Hier eine Lösung für meine obige Webseite:
@media screen and (max-width: 480px) { @-ms-viewport { width: device-width; } @-webkit-viewport { width: device-width; } @-moz-viewport { width: device-width; } @-o-viewport { width: device-width; } @viewport { width: device-width; }}@media screen and (max-width: 959px) and (min-width: 768px) { @-ms-viewport { width: device-width; } @-webkit-viewport { width: device-width; } @-moz-viewport { width: device-width; } @-o-viewport { width: device-width; } @viewport { width: device-width; }}
Ja, eine Schnupperstunde, so würde ich den Talk am letzten Montag zu Node.js auf dem Microsoft Web Summit 2013 bezeichnen. In der einen Stunde habe ich versucht die wichtigsten Aspekte der Entwicklung mit Node.js aufzuzeigen
wobei ich mich primär auf die Flexibilität durch Modularisierung fokussiert habe.
In meinem Vortrag habe ich eine Sache komplett außen vor gelassen: Testing. Ich kann nur nochmals betonen: Testen ist Lebenswichtig. Ich hebe meine Hand fürs Testing. Ich bin Pro Testing und beglückwünsche jeden Entwickler der das Tagtäglich lebt. Gerade im Umfeld mit dynamischen Sprachen ist Testing essentiell. Hier gibt es ebenfalls eine große Auswahl, die bekanntesten dürften Jasmine, Mocha und Chai sein, diese lassen sich noch mit Mocking Frameworks wie Sinon.js ergänzen.
Das Slidedeck gibt es hier, voila.
Wer Slides anderer Vorträge von mir sucht wird in Zukunft mehr Slidedecks auf meinem Speakerdeck finden.
Während des Vortrages habe ich die Anwendung Anfangs live gecodet, später über Schnipsel erweitert und zum Schluß ein fertiges Projekt genommen weil ich einen Fehler in einem meiner Code Files hatte welcher mir nicht gleich offensichtlich ins Auge stieß.
Auf jeden Fall vielen Dank an André, Christian und den 3. der mir beim Audience Pair Programming während der Session geholfen hat.
Was ich an Node wirklich cool finde ist die Möglichkeit sich sein System so zusammen zu stecken wie man es gerne möchte. Natürlich muss man hierfür schon wissen welche Module und Möglichkeiten es gibt und ich habe in der einen Stunde wirklich nur ganz rudimentäre Dinge gezeigt. Als Ausgangsbasis für eine kleine Musikplaylist habe ich den folgenden Code genommen
var http = require('http');var port = process.env.PORT || 5000;var server = http.createServer(function (req, res) { res.writeHead(200, { 'Content-Type': 'text/html' }); res.end('Hello from Node.js on Windows');});server.listen(port);
Es ist schon beeindruckend wie man mit 6 Zeilen Code einen einfachen HTTP Listener erstellen kann. Danach habe ich die Funktion in ein eigenes Modul ausgelagert.
(function() { "use strict"; function sayHello(req, res) { res.writeHead(200, { 'Content-Type': 'text/html' }); res.end('<h1>Hello from Node.js on Windows</h1>'); } exports.myFunction = sayHello;})();
Somit lassen sich einzelne Funktionspakete leicht in modulare Blöcke packen und entsprechend wiederverwenden. Die Verwendung des exports Statements sorgt dafür das die Funktion über den Modulnamen import erreicht werden kann.
exports
Der Server Code den ich in die app.js gepackt habe lädt nun das eigene Modul mittels require rein.
app.js
require
var http = require('http'), controller = require('./controller');var port = process.env.PORT || 5000;var server = http.createServer(function (req, res) { controller.myFunction(req, res);});server.listen(port);
Bis jetzt wird jeder HTTP Request an diesen Listener übergeben und es kommt immer das gleiche Resultat zurück. Es wird an der Zeit ein paar HTTP Routen zu definieren. Hierfür entscheide ich mich für das Modul director aus dem Flatiron.jsFramework. Das schöne an diesem Modul ist das es sowohl Serverseitig in Node.js funktioniert wie auch Client-seitig im Browser.
director
Module unter Node installiert man überlicherweise mit dem Node Package Manager kurz Npm. Npm greift auf npmjs.org zu, eine Registry in welche Entwickler eigene Module hinzufügen können. Um Director zu installieren gibt man einfach npm install director an und das Paket wird im Untervzeichnis node_modulesabgelegt.
npm install director
node_modules
Director ersetzt nun den Listener und macht ein Dispatch. Damit Director weiß wohin er weiterleiten kann müssen Routen definiert werden. Die Routen können direkt als Literal in der Instanzierung angegeben werden
var router = new director.http.Router({ '/about': { get: controller.myFunction }});
oder ad hoc
router.get('/', Controller.showRoot);
Nun hat man eine Abhängigkeit zu einem Modul geschaffen. Diese Abhängigkeit sollte man für seine Anwendung definieren, dazu gibt es eine weitere Datei die npmanalysiert: package.json.
npm
package.json
Diese Datei ist sozusagen das Manifest und enthält neben den Informationen zur Anwendung auch einen Bereich für Abhängigkeiten. Die externen Module kann man per npm install installieren. Für diese App sieht das package.json folgendermaßen aus:
npm install
{ "name": "DemoApp", "version": "0.1.0", "author": "writeline", "description": "This is just for a demo", "contributors": [ { "name": "Dariusz Parys", "email": "dparys@microsoft.com" } ], "main": "./app.js", "keywords": [ "azure", "demo" ], "dependencies" : { "director": ">=1.1.0", "jade": ">=0.28.1", "union": ">=0.3.6", "formidable": ">=1.0.11", "azure": ">=0.6.10" }, "noAnalyze": "true", "license": "Apache", "engines": { "node": ">=0.6.14" }}
>= sagt einfach aus, nimm alles von da an, auch wenn es neuer ist. Übrigens, das ist keine Best Practice, sondern lediglich während der Entwicklung interessant, speziell wenn man ein Modul als Abhängigkeit hat dass des Öfteren gefixed wird.
>=
Um die Routen zu verteilen muss noch der Router dispatchen
var server = http.createServer(function (req, res) { router.dispatch(req, res, function (err) { if (err) { res.writeHead(404); res.end(); } });});
Node hat sich nach der Version 0.1 von Promises verabschiedet und nimmt Callbacks her. Wer weiterhin mit Promises arbeiten möchte dem empfehle ich mal einen Blick auf das Github Repository von Dominic Denicola zu werfen.
In der Funktion weiter oben wurden die HTML Tags direkt im Response rausgeschrieben. Das will man nicht. Man will eine Viewengine. Und auch hier gibt es viele. Ich kann jedem empfehlen einen Blick auf Jade zu werfen.
Das HTML wird hier lediglich mit den Tag Namen beschrieben, Attribute in Klammern mit Kommas verpackt, Inhalte einfach dahintergeschrieben, Hierarchien durch Einrückungen (Whitespace) sichergestellt.
Die About Seite in Jade sieht so aus.
!!!html h1 Hello from Node.js on Windows
Fertig.
Analog die Einstiegsseite der Anwendung
!!!html h1 Microsoft Web Summit 2013 Demo h2 Simple Node.js coding div#main a(href='/about') About | a(href='/music') Music | a(href='/upload') Upload Music
Kurz und knackig.
Um das Template auch anzuzeigen könnte die Implementierung der showRootFunktion nun so aussehen:
showRoot
exports.showRoot = function () { var res = this.res, req = this.req; var path = __dirname + '/root.jade'; var content = fs.readFileSync(path, 'utf8'); var renderFunction = jade.compile(content, { filename: path, pretty: true }); res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(renderFunction());}
Man bekommt eine Funktion zum Rendern des Templates zurück. In diese Funktion können auch Objekte übergeben werden die in der View für Anzeigelogik Verwendung finden. Zum Beispiel die Anzeige der Musikstücke funktioniert auf diese Weise, übergeben werden die gefunden Musikblobs aus Windows Azure
res.end(renderFunction({blobs: blobs}));
und im Jade Template wird darüber iteriert
!!!html h1 Available music ul each blob in blobs li #{blob.name} audio(controls, src='#{blob.url}')
Eine der weiteren Stärken von Node.js ist das Streaming. Hier gibt es bereits Beispiele in der Praxis die Produktive Dienste aufgebaut haben.
Einen Hacken gibt es beim bestehenden Code: Buffering. Insofern wird noch eine Middleware benötigt über die ich das Buffering ausstelle und director integriere. Hier kommt union zum Einsatz.
union
Die Definition des Servers sieht nun ein wenig anders aus:
var server = union.createServer({ buffer: false, before: [ function (req, res) { var found = router.dispatch(req, res); if (!found) { res.emit('next'); } } ]});
Das ist der Grundstein damit die Datei gestreamed empfangen werden kann, für das Post Handling nehme ich das Modul formidable. Es benutzt Events auf welche ich lauschen kann um dann darauf zu reagieren:
formidable
exports.upload = function () { var res = this.res, req = this.req; var form = formidable.IncomingForm(); form .on('file', function (field, file) { var options = { contentType: file.type }; console.log("file path: " + file.path); }) .parse(req, function (err, fields, files) { res.writeHead(200, { 'Content-Type': 'text/plain' }); if (err) { res.end('error: Upload failed'); } else { res.end('sucess: Uploaded file(s) ' + util.inspect({ fields: fields, files: files })); } });}
Die Route kann Streaming empfangen sobald man dies dem Router mitteilt:
router.post('/upload', { streaming: true }, controller.upload);
Die Dateien werden in ein Temporäres Verzeichnis gespeichert. Von dort möchte ich diese in den Windows Azure Blob Storage packen. Die Schritte sind wirklich simpel an dieser Stelle. Zum einen erstelle ich einen Blob Storage Client und übergebe diesem den API Key zur Verbindung. Der folgende Code Schnipsel zeigt die Definition der Umgebungsvariablen und dem Anlegen eines Containers falls dieser noch nicht existiert:
process.env.AZURE_STORAGE_ACCOUNT = "xyz";process.env.AZURE_STORAGE_ACCESS_KEY = "xyz";var blobService = azure.createBlobService();blobService.createContainerIfNotExists('uploads', { publicAccessLevel: 'blob' }, function (error) { if (error) { console.dir(error); return; }});
Um einen Blob in den Container zu legen muss man lediglich die folgende Zeile im file Event von Formidable hinzufügen
file
blobService.createBlockBlobFromFile('uploads', file.name, file.path, options, function (error) { if (error) { console.dir(error); }})
Das Deployment Model ist mit Windows Azure Websites simpel. Ich habe ein Github Repository mit der Windows Azure Website verbunden. Bei jedem git push origin master wird automatisch auf die Webseite verteilt und die Seite steht kurze Zeit später im Web live zur Verfügung.
git push origin master
Das komplette Beispiel aus dem Talk findet ihr hier auf Github.
Near Field Communications (NFC) erlaubt die Kommunikation auf kürzester Distanz zwischen zwei Endgeräten um kleinere Datenmengen auszutauschen oder andere Verbindungen auf Basis der NFC Verbindung herzustellen.
NFC wird bereits heute im Consumer Umfeld eingesetzt. Als Beispiel soll hier der Lautsprecher Nokia Play 360 dienen. Dieser wird mittels NFC mit einem Smartphone verbunden.
Ist die Initiale Verbindung hergestellt, so kommuniziert das Smartphone weiter über Bluetooth um seine Musik an den Lautsprecher zu streamen oder die Lautstärke anzupassen. Hier wird NFC also nur für eine Initiale Verbindung genutzt um die Einrichtung der Bluetooth Verbindung zu vereinfachen.
Neben Geräten die per NFC angesprochen werden können, kann ein Smartphone auch mit einem NFC Tag kommunizieren. Ein solches Tag kann in verschiedenen Formen daherkommen: Armbänder, Schlüsselanhänger oder einfach nur als Papier Sticker.
Auf ein solches Tag können unterschiedlich viele Informationen geschrieben werden, letztlich ist die Begrenzung nur anhand des verfügbaren Speicherplatzes beschränkt. Hier ist Speicher wirklich noch klein. Ich zum Beispiel habe NFC Tags mit einer Speichergröße von 168 Byte, es gibt aber auch 1k bzw. 4k Tags. Andere Größen mögen auch möglich sein, das sind die mir bekannten.
Da die Datenmenge von solchen Tags stark begrenzt ist dienen diese häufig als Einstiegspunkt für andere Dienste. Ähnliches kennt man schon heute aus einem anderen Bereich: QR Codes. Mit QR Codes werden einfache Textinformationen dargestellt, in der Regel ist es eine URL. Anders als beim QR Code lässt sich Information auf einem NFC Tag auch verändern und neu beschreiben.
Um nun mit NFC Tags kommunizieren zu können benötigt man zuerst einmal einige Dinge, ich gehe hier nun von meinem Beispiel aus
Einfach NFC Tags in die Suchmaschine seiner Wahl eingeben und einen geeigneten Shop suchen. Ich gebe hier mal keine Empfehlung, weil ich meine eigenen Tags von einem Kollegen geschenkt bekommen habe.
Um mit dem Windows Phone 8 NFC Tags anzuprogrammieren sollten diese NDEF formattiert sein. Raw Level Funktionen stellt die Windows Phone 8 API nicht zur Verfügung.
Das bringt uns gleich zu einem weiteren Problem das ich an dieser Stelle kurz erwähnen möchte. Die Tags lassen sich über die Plattform API’s nicht RAW beschreiben und damit kann man das Tag nicht schreibschützen. Wenn Ihr Szenarios habt die ein schreibgeschütztes Tag benötigen, so gibt es Händler die Tags bespielen und schreibgeschützt ausliefern. Auch hier einfach mal schauen was der einzelne an Angebote hat.
Im Namensbereich Windows.Networking.Proximity befindet sich der Einstiegspunkt um NFC Tags zu lesen, die wichtigste Klasse hierbei ist ProximityDevice. Bei dem Lumia zeigt der folgende Code NFC fähige Tags und Geräte an:
Windows.Networking.Proximity
ProximityDevice
var proximityDevice = ProximityDevice.GetDefault();proximityDevice.DeviceArrived += proximityDevice_DeviceArrived;void proximityDevice_DeviceArrived(ProximityDevice sender){ if (sender != null) { Dispatcher.BeginInvoke(() => { theOutput.Text = sender.DeviceId; }); }}
Für den eigentlichen Datenstrom benötigt man noch einen Eventhandler der auf ndef Nachrichten lauscht.
ndef
NDEF steht für NFC Data Exchange Format
Hier lassen sich auch Daten für andere Plattformen erstellen und so Cross-Plattform Übergreifend auch nutzen.
proximityDevice.SubscribeForMessage("ndef", handler);private void handler(ProximityDevice sender, ProximityMessage message){ // hier wird die Nachricht ausgewertet}
Die Windows Phone 8 API untertstützt URI’s. Für NDEF gibt es auf Codeplex eine Bibliothek die man mittels Nuget installieren kann.
Die NDEF Bibliothek von Andreas Jakl erleichtert die Auswertung von NDEF Nachrichten. Einziger Wehrmutstropfen: Das Package über Nuget lässt sich nicht in Visual Studio 2012 Express für Windows Phone 8 installieren. Grund dürfte hierfür die Portable Class Library sein mit der die Funktionalität bereitgestellt wird, bei der Installation wird darauf hingewiesen.
Die Inhalte der Tags lassen sich nun über den eingerichteten Handler mit Hilfe der NDEF Library einfach auslesen:
private void handler(ProximityDevice sender, ProximityMessage message){ StringBuilder builder = new StringBuilder(); builder.AppendLine(); var rawMessage = message.Data.ToArray(); var ndefMessage = NdefMessage.FromByteArray(rawMessage); foreach (var record in ndefMessage) { builder.AppendFormat("Record type " + Encoding.UTF8.GetString(record.Type, 0, record.Type.Length)); } Dispatcher.BeginInvoke(() => { theOutput.Text += builder.ToString(); });}
Meine Tags sind mit einer URL bespielt, so bekommt man als Ergebnis Record type U zurück. Auf einem Tag können mehrere Einträge vorhanden sein. Zum Beispiel könnten für jedes Smartphone Betriebssystem einzelne Datensätze zur eigenen Anwendung abgelegt sein um diese zu starten, um Features zu nutzen die für die jeweilige Plattform einzigartig sind.
Record type U
Die Inhalte werden anhand von einzelnen Datensätzen geschrieben. Ein Datensatz umfasst in der Regel das Protokoll das genutzt wird, z.B. tel für das Telefon, smsfür eine SMS, etc… Zum anderen können zusätzliche Informationen in einen solchen Datensatz gepackt werden um den Konsumenten des Tags anzuzeigen was passieren wird wenn er die Aktion des Tags annimmt.
tel
sms
Einen Telefonanruf kann man auf einen Tag folgendermaßen schreiben:
var phoneRecord = new NdefTelRecord();phoneRecord.TelNumber = "0123456789";phoneRecord.NfcAction = NdefSpActRecord.NfcActionType.DoAction;var message = new NdefMessage{ phoneRecord};proximityDevice.PublishBinaryMessage("NDEF:WriteTag", message.ToByteArray().AsBuffer());
Das ist im Prinzip schon alles um auf Tags Informationen zu schreiben und zu lesen. Durch die NFC Technik werden manche Szenarien ermöglicht die bisher einen höheren technischen Aufwand bedeutet haben. Von Exponaten in Museen die mit NFC Tags angereichert sind um Textinformationen auf das Smartphone des Besuchers in seiner Sprache wiederzugeben, bis hin zu Spielen die reale Orte mit virtuellen Welten über NFC Tags verknüpfen können oder Kassensystemen die per NFC den Bezahlvorgang initiieren. Letztlich liegt es an den Szenarien ob sich eine Technologie verbreitet, NFC hat auf jeden Fall das Potential dazu.
Als Frontend-Webentwickler ist man mit den Browser Debugging Tools bestens vertraut. Sei es die Developer Tools vom Internet Explorer oder Firebug für Firefox. Mit Hilfe der Developer Tools lassen sich schnell Variablen prüfen, DOM Elemente sichten und on-the-fly Zuweisungen in der Console durchführen.
Und genau die gleiche Art von Tooling gibt es auch für Windows Store Apps die mit HTML5 / JavaScript geschrieben werden. Oder anders: für WinJS Apps.
Speziell das Sichten der Elemente im DOM Tree ist wichtig um bestimmte CSS Regeln und deren Anwendung zu finden. Dies ist dann besonders nützlich wenn man WinJS UI Controls verwendet. Aus dem kleinen HTML Schnipsel hier unten
<section aria-label="Main content" role="main"> <div id="list" data-win-control="WinJS.UI.ListView"></div></section>
wird zur Laufzeit dieses HTML generiert
<div tabindex="-1" class="win-listview win-swipeable" id="list" role="listbox" style="position: relative;" data-win-control="WinJS.UI.ListView"> <div tabindex="-1" class="win-viewport win-horizontal" role="group" aria-label="Scrolling Container"> <div id="ms__id3" aria-flowto="ms__id4"></div> <div class="win-surface"> <div class="win-backdrop" aria-hidden="true" style="width: 0px; height: 0px;"></div> <div class="win-backdrop" aria-hidden="true" style="width: 0px; height: 0px;"></div> <div class="_win-proxy"></div><div tabindex="0" aria-hidden="true"></div> <div style="left: 0px; top: 0px; width: 100%; height: 100%; position: absolute;"></div> <div tabindex="0" aria-hidden="true"></div> </div> <div id="ms__id4" x-ms-aria-flowfrom="ms__id3"></div> </div> <div tabindex="0" aria-hidden="true"></div> <div aria-hidden="true" style="left: 50%; top: 50%; position: absolute;"> <div aria-hidden="true" style="width: 0px; height: 0px;"></div> </div> <div tabindex="0" aria-hidden="true"></div></div>
Dies geschieht durch die Instanzierung des WinJS Controls das mittels des Attributesdata-win-control="WinJS.UI.ListView" definiert ist. Je nach Control werden zusätzliche HTML DOM Elemente angehängt und Funktionalität mit diesen verknüpft. Im obigen erzeugten HTML sieht man auch neue CSS Klassen, zum Beispiel win-backdrop. Diese CSS Klassen haben ein vordefiniertes Look & Feel das zum Gesamterscheinungsbild des Controls passt. Es gibt eine Vielzahl solcher CSS Klassen die in der Visual Studio Hilfe beschrieben sind. Diese Klassen kann man dann als Anker nehmen um eigenes Styling durchzuführen.
data-win-control="WinJS.UI.ListView"
win-backdrop
Möchte man nun nachschauen wie das momentane Live DOM der Anwendung aussieht so startet man die Anwendung im Debug Mode aus Visual Studio und wechselt mittels ALT TAB zurück in die Entwicklungsumgebung. Im Reiter DOM Explorer hat man das DOM im Überblick sowie auch die angewendeten CSS Regeln.
ALT
TAB
DOM Explorer
Möchte man ein bestimmtes UI Element im DOM finden so kann man das über die Select Element Funktionalität machen.
Select Element
Die Anwendung erscheint und man kann das Element auswählen welches man begutachten möchte
Mit Hilfe der Developer Tools in Visual Studio 2012 hat man die gleichen Debugging Möglichkeiten wie man diese vom Browser her kennt. Es liegt allerdings eine leichte Lernkurve in der Verwendung der WinJS Controls, speziell wenn es um das Styling dieser geht.
Ende November habe ich angefangen eine Windows Store App in HTML5 und JavaScript zu entwickeln und dabei den Fortschritt in Form von Videos zu dokumentieren. Die App nennt sich My Diablo 3 und ist ein einfacher Frontend für die Diablo 3 Blizzard Webseite. Die App ist seit heute im Store und kann über den folgenden Link bezogen werden
Windows Store App: My Diablo 3
Neben den RSS Feeds können auch Karrieren über das Battletag eines Spielers begutachtet werden. Von der Idee der App bis zum Submit in den Windows Store sind die einzelnen Schritte Stück für Stück in den einzelnen Videos der Playliste My Diablo 3 - Eine Windows 8 programmieren nachzuvollziehen.
Der Hauptbestandteil der Anwendung sind die Dienste von Blizzard. Ohne diese Dienste funktioniert die App einfach nicht. Um auf die Dienste zuzugreifen habe ich einen sehr einfachen Zugriffslayer geschrieben den ich auf Github publiziert habe.
Diablo 3 WinJS Api
Natürlich gibt es noch einen Haufen Todos
Es gibt Stand heute nicht einen Unit Test oder Integration Test für diese App. Ich weiß, Testing ist essentiell, ich bekenne mich schuldig.
Ich cache absolut nichts. Die App funktioniert nur mit verbundenem Internet und wird auch einen Fehler anzeigen wenn das Netzwerk nicht verfügbar ist.
Momentan ist die App nur in deutsch Verfügbar. Eine englische Variante wäre gut, damit könnte man in alle Märkte weltweit publizieren
Wer sich seine Helden anschaut der wird feststellen das nur Basisdaten angezeigt werden. Von den einzelnen Ausrüstungsgegenständen werden nur die wichtigsten Werte angezeigt. Mehr Detailtiefe wäre gut.
Ich habe mir zwar Gedanken zu der Navigation gemacht, würde aber Stand heute die Karriere und die Helden strikter trennen und nicht in einer einzigen Flexbox aneinanderreihen. Doch dieses Refactoring macht mir Angst, insofern lasse ich mir damit erstmal ganz viel Zeit.
All diese Dinge sind für eine kostenfreie App natürlich viel Arbeit in der Freizeit.
Die Zeit ist eigentlich der springende Punkt. Wenn es App Ideen gibt für die man kein Geld verlangen möchte - in diesem Fall dürfte ich nicht einmal - so liegt es nahe sich mit mehreren Leuten zusammen zu schliessen und die App weiterzuentwickeln. Ich weiß nicht ob der Open Source Gedanke für Apps auch funktionieren kann, einen Versuch wäre es aber Wert.
Zumindest werde ich die Lokalisierung noch finalisieren und den Code aufräumen, einen letzten zehnten Teil aufnehmen und den Code dann veröffentlichen. Dann steht Fork und Pull Request nichts mehr im Wege.
Seit dem 26.10 ist nun Windows 8 verfügbar. Erstmalig integriert ist der Windows Store. Der Store ist das Distributionsmittel für Windows Store Apps. Apps können kostenlos sein, Funktionen über In-App Purchase verfügbar machen, können Werbung integrieren oder einfach kommerziell erworben werden.
In diesem Post geht es nicht um technische Implementierungsdetails eines In-App Purchase, auch nicht welche Bezahlinfrastruktur genommen werden soll, vielmehr möchte ich auf die Preisfindung für die eigene App eingehen. Während der Preview Phase von Windows 8 war es nicht ersichtlich wie sich die Preise für Apps entwickeln, in der Preview waren alle Apps kostenfrei. Seit dem Release können Apps nun regulär erworben werden und damit zeichnet sich auch ein erstes Bild für die Preisentwicklung ab. Schaut man momentan in den Store und nur auf die kostenpflichtigen Anwendungen, so hat man das Gefühl man befindet sich Preistechnisch auf einer Phone Plattform.
Windows Store Apps sind zu günstig (Stand 11.08.12)
Unabhängig von der Bezahlinfrastruktur, ob unsere oder eine andere. Apps sind zu günstig.
Natürlich ist der Preis wirklich davon abhängig um was für eine Anwendung es sich handelt, wieviele parallele Apps es gibt die ähnliches machen, wie die Entwicklungskosten sind, welchen Zweck die App für das eigene Unternehmen erfüllen soll, usw. Was viele scheinbar nicht in die Preisfindung einkalkulieren ist die Tatsache das es sich um den gleichen Store handelt - für Windows 8 wie auch für Windows RT.
Der Benutzer gibt bei einem wertigen Gerät mehr Geld für Apps aus
Boom. Ist ein Behauptung von mir, nichts was ich statistisch beweisen kann. Wobei, ein wenig unterlegen kann ich es schon.
Für beide Betriebssysteme gibt es jeweils einen Store. Es gibt Statistiken die Aussagen wieviele Apps im Durchschnitt ein iPad User besitzt usw. Man muss aber gar nicht so tief reingehen, man schaut sich einfach mal die Preise für beide Stores für die gleichen Produkte an.
Fairerweise muss man sagen das die Produkte nicht ganz in der Funktionalität identisch sind, wie z.B. Pages, was unter anderem daran liegt das die Plattformen sich technisch unterscheiden.
Bei Windows 8 sieht das anders aus. Eine Windows Store App läuft sowohl auf einer fetten Windows 8 High Performance Workstation wie auch auf einem Tablet mit Windows RT. Und genau dieser Unterschied sollte in die Preiskalkulation mit einfließen. Ein Benutzer kann die App sowohl auf seinem Tablet wie auch auf seinem Desktop PC nutzen. Insgesamt kann er die gleiche App auf 5 Geräten nutzen.
Harry Wijnvoord’s berühmter Satz Das wäre Ihr Preis gewesen sollte man sich nochmal durch den Kopf gehen lassen wenn man den Preis für eine App kalkuliert. In den nächsten Wochen und Monaten wird in Richtung Preisfindung im Store mit Sicherheit eine Bewegung zu beobachten sein. Falls diese nach oben geht und man zu tief angesetzt hat ist das ärgerlich. Hätte man eine wirklich beliebte App für 2.49€ in den Store gestellt und die Preise würden anziehen, so könnte man nicht mal nachziehen. Ich meine technisch geht das schon, aber es zieht eine kleine Welle der Kritik mit. Manchmal wird aus der Welle auch ein Tsunami und das ist mit Sicherheit etwas was man nicht möchte. Viel besser ist es im Store mit einem höheren Preis einzusteigen und gegebenfalls den Preis in Aktionen zu reduzieren. Das kommt beim Konsumenten um längen besser an.