Markus Spiering / Sven Haiges
Know-how ist blau.
HTML5-Apps für iPhone und Android > So gestalten Sie das „Look and Feel“ für iPhone- und Android-Apps mit HTML5 und CSS > Bauen Sie mit JavaScript aktuelle Geodaten, Videos und Grafiken in Ihre Apps ein! > Wandeln Sie Ihre Apps mit PhoneGap in native Applikationen für das iPhone und Android-Smartphones um!
Markus Spiering / Sven Haiges
HTML 5-Apps für iPhone und Android entwickeln
Markus Spiering / Sven Haiges
HTML 5-Apps für iPhone und Android entwickeln
Mit 214 Abbildungen
Bibliografische Information der Deutschen Bibliothek Die Deutsche Bibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte Daten sind im Internet über http://dnb.ddb.de abrufbar.
Alle Angaben in diesem Buch wurden vom Autor mit größter Sorgfalt erarbeitet bzw. zusammengestellt und unter Einschaltung wirksamer Kontrollmaßnahmen reproduziert. Trotzdem sind Fehler nicht ganz auszuschließen. Der Verlag und der Autor sehen sich deshalb gezwungen, darauf hinzuweisen, dass sie weder eine Garantie noch die juristische Verantwortung oder irgendeine Haftung für Folgen, die auf fehlerhafte Angaben zurückgehen, übernehmen können. Für die Mitteilung etwaiger Fehler sind Verlag und Autor jederzeit dankbar. Internetadressen oder Versionsnummern stellen den bei Redaktionsschluss verfügbaren Informationsstand dar. Verlag und Autor übernehmen keinerlei Verantwortung oder Haftung für Veränderungen, die sich aus nicht von ihnen zu vertretenden Umständen ergeben. Evtl. beigefügte oder zum Download angebotene Dateien und Informationen dienen ausschließlich der nicht gewerblichen Nutzung. Eine gewerbliche Nutzung ist nur mit Zustimmung des Lizenzinhabers möglich.
© 2010 Franzis Verlag GmbH, 85586 Poing Alle Rechte vorbehalten, auch die der fotomechanischen Wiedergabe und der Speicherung in elektronischen Medien. Das Erstellen und Verbreiten von Kopien auf Papier, auf Datenträgern oder im Internet, insbesondere als PDF, ist nur mit ausdrücklicher Genehmigung des Verlags gestattet und wird widrigenfalls strafrechtlich verfolgt. Die meisten Produktbezeichnungen von Hard- und Software sowie Firmennamen und Firmenlogos, die in diesem Werk genannt werden, sind in der Regel gleichzeitig auch eingetragene Warenzeichen und sollten als solche betrachtet werden. Der Verlag folgt bei den Produktbezeichnungen im Wesentlichen den Schreibweisen der Hersteller. Herausgeber: Ulrich Dorn Satz: DTP-Satz A. Kugge, München art & design: www.ideehoch2.de Druck: Bercker, 47623 Kevelaer Printed in Germany ISBN 978-3-645-60052-1
5
Einführung Mit der Einführung des Apple iPhones im Jahr 2007 hat sich die mobile Welt komplett geändert: Internetdienste werden von einer großen Masse wie selbstverständlich genutzt, und der mobile Markt hat sich, anstatt sich auf eine oder einige wenige Plattformen zu konsolidieren, in Höchstgeschwindigkeit weiter fragmentiert. Apple hat mit dem iPhone und dem iPhone OS ein Erfolgsmodell geschaffen und ein unvergleichliches Wettrennen der mobilen Plattformen eingeläutet. Einige Jahre nach dem ersten iPhone haben wir folgende Situation: Die Verbindung von iPhone und iTunes hat ein Verkaufsmodell für mobile Anwendungen geschaffen, das Hunderttausende von Anwendungen für die iOS-Plattform hervorgebracht hat und Entwickler begeistert. Microsoft ist fast schon in der mobilen Bedeutungslosigkeit verschwunden und versucht, mit Windows Phone 7 wieder Marktanteile zu gewinnen. Handy-Weltmarktführer Nokia hat sich jahrelang auf seine Symbian-Plattform verlassen, unterstützt diese zwar weiter, entwickelt aber auch neue Multimedia-Telefone auf der Linux-basierten MeeGo-Plattform. BlackBerry hat keine andere Plattform lizenziert, sondern setzt weiterhin auf sein eigenes System. Palm, schon vor einigen Jahren tot geglaubt, hat zahlreiche Apple-Designer und -Techniker abgeworden und mit WebOS ein unglaublich performantes und zukunftweisendes mobiles Betriebssystem auf den Markt gebracht. Leider wird es bislang nur von Palm selbst benutzt, wobei der neue Eigentümer Hewlett-Packard hier sicher für weitere Verbreitung sorgen kann. Trotz dieser Plattformvielfalt gab Google im November 2007 bekannt, gemeinsam mit 33 Mitgliedern der sogenannten Open Handset Alliance ein weiteres mobiles Betriebssystem namens Android zu entwickeln. Ohne die hausgemachten Systeme von Samsung, LG und anderen Herstellern, besonders aus dem asiatischen Raum, zu erwähnen, kommen wir mit dem Apple iOS, Android, Windows Phone 7, BlackBerry, Symbian, MeeGo, Web OS und mobilen Linux-Versionen auf acht verschiedene nennenswerte Handyplattformen. Zur gleichen Zeit hat sich mit dem iPhone die Handynutzung verändert: Während man Telefone zuvor größtenteils zum Telefonieren, Verfassen von Textnachrichten oder zum Checken von E-Mails verwendete, wurde das iPhone als erstes Telefon serienmäßig mit einem Browser ausgeliefert, der dem eines Browsers auf dem PC in nichts nachsteht und mit dem App-Model und der iTunes-Anbindung den angestaubten Markt von mobilen Anwendungen auf den Kopf gestellt hat. Ein Verkaufsargument für Handys ist heute nicht mehr nur der bessere Bildschirm oder die bessere Kamera, sondern auch, welche Art von Diensten ich auf dem Gerät bzw. der Plattform nutzen kann. Kann ich das Telefon mit iTunes verbinden und meine Musik synchronisieren? Kann ich meinen Facebook-Status aktualisieren, meine Fotos direkt auf Flickr laden und mit meinen Freunden und Bekannten direkt vom Telefon aus teilen? Wie viele Programme und auch Spiele gibt es eigentlich für mein Telefon?
6
Einführung
Und hier beginnt genau das Problem für Handyhersteller, für Anwender und auch für Anbieter von Programmen und Diensten. Alle Hersteller, außer derzeit Apple, haben Probleme, im großen Rahmen Entwickler für ihre Plattform zu finden und zu begeistern. Waren mobile Softwareentwickler vor ein paar Jahren noch kaum beachtet, so sind sie jetzt heiß umworbene Dienstleister. Alle Systemhersteller betreiben einen riesigen Aufwand, um Entwickler davon zu überzeugen, mit ihrem System zu arbeiten und Programme und Dienste zu schreiben. Gleichzeitig müssen sich Anbieter von Diensten und Programmierer die Frage stellen, auf welche Plattformen sie sich konzentrieren sollen. Alle Plattformen sind grundverschieden, und Code, der für das iPhone geschrieben wird, kann nicht einfach für Android oder das Symbian-Betriebssystem wiederverwendet werden. Die Entwicklung von mobilen Diensten ist für Firmen notwendig, da der mobile Markt viel verspricht, aber bislang nur wenig abwirft. Gleichzeitig ist die Entwicklung von mobilen Programmen sehr teuer, sollte von mobilen Softwarespezialisten vorgenommen werden und verursacht allein durch das Testen auf verschiedenen Telefonen hohe Kosten. Keine Firma wird so einfach bereit sein, gleichzeitig in alle acht Plattformen zu investieren, sondern sich höchstens zwei oder maximal drei unterschiedliche Versionen leisten. Doch es gibt Hoffnung: Neben großen, hochauflösenden Bildschirmen und tollen Kameras werden alle Handys in naher Zukunft eine Gemeinsamkeit aufweisen: unwahrscheinlich gute Webbrowser, die sich an die neuesten Standards richten. Der neueste Webstandard, der von den gängigen Webbrowsern mehr und mehr unterstützt wird, ist HTML5. Glücklicherweise wird sich HTML5 von der HTML 4-Spezifikation insbesondere dadurch unterscheiden, dass sich mit der neuen Version Webdienste erstellen lassen, die nicht nur wie richtige Programme aussehen, sondern sich auch wie Programme verhalten. Auf Inhalte einer Webseite kann auch dann zugegriffen werden, wenn keine Internetverbindung vorhanden ist, auf das Dateisystem kann vom Internetbrowser aus zugegriffen werden, und die aktuelle Position des Benutzers ist ebenfalls ab sofort für eine Internetseite kein Geheimnis mehr. Alle diese Funktionen konnten früher nur von richtigen Programmen, aber nie von Internetseiten verwendet werden. Mit den genannten Problemen und der starken Fragmentierung des mobilen Markts, aber auch durch die herausragenden Möglichkeiten, die moderne, mobile Webbrowser und der HTML5-Standard bieten, muss man annehmen, dass insbesondere im mobilen Bereich HTML5 einen enormen Einfluss nehmen wird. Für Dienstanbieter ist dies ein Glücksfall: Sie können auf vorhandene Webprogrammierer zurückgreifen, mit einer mobilen Webanwendung in HTML5 sicherstellen, dass sie einen sehr guten Dienst auf allen mobilen Plattformen anbieten, und sie können sich immer noch entscheiden, eine native Anwendung für beispielsweise den iPhone App Store oder den Android Market programmieren zu lassen. Und das ist auch gar nicht schwer: Mittlerweise gibt es mit dem PhoneGap (www. phonegap.com) und dem Appcelerator Titanium Mobile (www.appcelerator.com) Technologien, die aus HTML5-Webanwendungen native Anwendungen für die gängigsten mobilen Plattformen bauen. Insbesondere mit PhoneGap lassen sich im Handumdrehen richtige Anwendungen erstellen, die sich nicht nur in den App Stores verkaufen, sondern auch mit Funktionen bereichern lassen, die im Browser gar nicht zur Verfügung stehen. Die Bewegungssensoren, die Kamera, der Vibrationsalarm, der Kompass, das Adressbuch und vieles
Einführung
7
mehr lassen sich über ein paar simple JavaScript-APIs direkt vom PhoneGap-HTML-, CSS- und JavaScript-Code aus steuern. All diese Technologien und Ansätze möchten wir Ihnen auf den nächsten gut 300 Seiten vorstellen. Am Ende des Buchs haben Sie nicht nur ein umfassendes Wissen über HTML5, sondern auch das Zeug, Ihre erste iPhone App oder Android-Anwendung in iTunes bzw. dem Android Market zu veröffentlichen.
Worum geht es hier? Dieses Buch ist kein Programmierbuch im klassischen Sinn. Es gibt Ihnen einen Einblick in Designkonzepte von mobilen Webdiensten und hilft Ihnen, erste Webanwendungen mittels HTML, CSS und JavaScript zu erstellen. Diese Webanwendungen werden bereits ein richtiges »iPhone-Look & Feel« besitzen. Ein großer Teil des Buchs beschäftigt sich mit den neuen Funktionen und Möglichkeiten von HTML5 und zeigt diese im mobilen Kontext eindrucksvoll und verständlich an vielen Beispielen. Der letzte Teil des Buchs beschreibt Schritt für Schritt, wie Sie eine HTML5-Webanwendung in echte iPhoneoder Android-Anwendungen umwandeln und dabei Telefonhardwarefunktionen wie die Kamera oder den Bewegungssensor eines iPhones oder Android-Smartphones ausnutzen. Abschließend erfahren Sie, wie Sie Ihre frisch gebaute Anwendung dann auch in den Apple Store und in den Android Market bekommen. Die Twitter-Updates zum Buch Folgen Sie @html5togo auf Twitter – http://twitter.com/html5togo –, um neueste Updates und interessante Artikel zum Thema HTML5 und Mobile direkt von den Autoren des Buchs zu erhalten und mit diesen in Kontakt zu treten.
HTML5 – die Spezifikation und der aktuelle Stand Streng genommen, ist HTML5 die sich noch in Entwicklung befindliche neue Version des HTML-Standards. Wie auch HTML 4.1 und XHTML 1.1 ist HTML5 eine standardisierte Markup-Sprache, die dazu dient, Webinhalte zu strukturieren und zu präsentieren. Rein technisch gesehen, ist HTML5 aber eben HTML und nicht JavaScript und auch nicht CSS. Doch die Masse versteht unter HTML5, speziell unter dem Begriff »HTML5 Web Apps«, etwas anderes. HTML5 ist zum Schlagwort einer (begrüßenswerten) Entwicklung geworden und beschreibt Anwendungen, die mit Webstandards, also HTML, CSS und JavaScript, geschrieben werden und in den Browsern auf unterschiedlichen Plattformen laufen. HTML5 steht für Webseiten, die sich wie Anwendungen anfühlen, wie Anwendungen gestartet werden können und weit in den Bereich nativer Anwendungen reichen. Wir versuchen in diesem Buch, die richtige Balance zu finden zwischen neuen Funktionen, die sich wirklich auf HTML5 als Markup-Sprache beziehen, und den Möglichkeiten, die durch die Vermischung von HTML, JavaScript und CSS entstehen und eben auch als »HTML5« bezeichnet werden.
8
Einführung
Auch wenn Sie überall schon von HTML5 hören, heißt das noch nicht, dass die neue Version des HTML-Standards bereits fertig ist. Im Gegenteil: HTML5 ist derzeit noch in der »Working Draft«-Phase, einem Stadium, in dem immer noch aktiv an der Definition der Sprache gearbeitet wird. Allerdings werden nicht alle Komponenten, also nicht alle Tags, gleichzeitig bearbeitet, und bestimmte Teile der Sprache sind bereits weiter vorangeschritten als andere. Komponenten wie beispielsweise das canvas-Tag sind sehr stabil und nahezu »fertig«, während andere Teile der Sprache noch gar nicht definiert wurden. Der Entwicklungszyklus einer neuen HTML-Definition bewegt sich im Bereich von 20 Jahren. Mit der HTML5-Spezifizierung wurde 2004 unter dem Namen »Web Applications 1.0« begonnen, und es wird derzeit erwartet, dass die Sprache im Jahr 2022 die offizielle W3C-Empfehlung erhalten wird. Zum Vergleich: Die derzeit gültige HTML5Spezifikation wurde Mitte der 90er-Jahre begonnen. Nun sollten Sie auf keinen Fall bis 2022 warten, sondern die Möglichkeiten von HTML5 und den oft in einem Atemzug genannten Technologien JavaScript und CSS schon heute nutzen. HTML5 ist bereits da, wird aber in der Zukunft noch wesentlich umfangreicher und von mehr Plattformen und Browsern unterstützt werden, als es heute der Fall ist. Die hier im Buch vorgestellten HTML5-Methoden sind bereits größtenteils von den führenden mobilen Plattformen implementiert, ganz vorn dabei natürlich iOS und Android, aber auch BlackBerry OS 6. Lesezeichen http://dev.w3.org/html5/spec/ Offizielle HTML5-Spezifikation: In diesem Buch wird die offizielle HTML5-Spezifikation immer in einem mobilen Umfeld betrachtet. Falls Sie sich für die komplette Spezifikation interessieren, finden Sie sie hier.
Webanwendung vs. native Anwendung Bereits weiter oben wurde häufig von einer Webanwendung und einer »richtigen« nativen Anwendung gesprochen. Auch wenn HTML5 die Grenzen und Möglichkeiten zwischen einem richtig programmierten Programm und einer Webseite verschwimmen lässt, so gibt es doch einige nennenswerte Unterschiede, die zu bedenken sind.
Native Anwendung Unter einer nativen Anwendung versteht man ein Programm, das nicht im Browser des Telefons (oder eines Computers) läuft, sondern als eigenständiges Programm auf das Gerät geladen wurde und ein richtiges Computerprogramm ist. Native Anwendungen haben in der Regel einen besseren Zugriff auf Systemfunktionen, wie beispielsweise die Kamera eines Handys oder Bewegungssensoren, können Rechenoperationen viel schneller ausführen und die Grafikmöglichkeiten eines Systems wesentlich besser ausnutzen. Sämtliche Spiele, die auf schnelle Grafikroutinen angewiesen sind, werden als native Anwendungen erstellt.
Einführung
9
Diese Anwendungen haben gegenüber Webanwendungen nicht nur auf der technischen Seite Vorzüge, sondern bieten einen riesigen Vorteil: Man kann sie in die App-Stores der verschiedenen Plattformanbieter einstellen. Distribution ist das Zauberwort! Eine native Anwendung kann beispielsweise im iPhone App Store eingestellt, beworben und vertrieben werden. Benutzer müssen nicht umständlich im Internet nach ihrer mobilen Webseite suchen, sondern finden ein fertiges Programm zum Installieren in iTunes oder im App Store des iPhones. Die Wahrscheinlichkeit, dass ein Kunde Ihren Dienst in einem App Store entdeckt, ist wesentlich höher, als wenn er bei Google oder Yahoo! danach sucht. Ein zusätzlicher Bonus: Nach dem Hinzufügen ist das Programm direkt auf dem Home-Bildschirm des iPhones oder Android-Handys verewigt. Dies alles klingt gut, und Sie werden sich jetzt vielleicht fragen, warum Sie sich kein Buch zur iPhone-Programmierung mit Objective-C gekauft haben, doch leider ist nicht alles so einfach: •
Der Aufwand, eine native Anwendung zu erstellen, ist pro Plattform immens hoch. Zwar kann es Ihnen gelingen, auf einer Plattform eine hohe Reichweite Ihrer Anwendung und Ihres Angebots zu erreichen, allerdings bedienen Sie nur eine von vielen Plattformen.
•
Bevor Ihre Anwendung in einem der bekannten App-Stores erscheint, muss sie einen Genehmigungsprozess durchlaufen. Dies gilt nicht nur, wenn Ihre Anwendung erstmalig eingestellt wird, sondern der Prozess muss bei jeder Aktualisierung wiederholt werden.
Der Genehmigungsprozess, insbesondere um in den iPhone App Store zu kommen, wurde in der Presse schon oft heiß diskutiert. Selbst Internetgrößen wie Google wurde der Eintritt in den Store beispielsweise mit der Google Voice-Anwendung verwehrt. Interessanterweise hat sich Google damit beholfen, eine Webanwendung mit HTML5 – www.youtube.com/watch?v=neiOa38DuqI – zu erstellen, die fast identische Funktionen wie die eigentliche native Anwendung auf das iPhone bringt. Viele Entwickler warten bislang oft mehrere Wochen, bis ihre Anwendung im App Store erscheint oder genehmigt wird. Warum eine App bei Apple abgelehnt wurde, wird in der Regel nicht sehr detailliert begründet. Wie bereits gesagt, ist eine Überprüfung sogar bei jeder neuen Programmversion erforderlich. Wenn Ihre Anwendung beispielsweise einen Fehler enthält, kann er nicht einfach wie bei einer Webseite sofort behoben werden. Stattdessen müssen Sie ein neues Anwendungspaket bauen, dieses Paket auf verschiedenen Telefonen testen, es an Apple oder einen anderen Betreiber des App Store übermitteln, auf das Testergebnis warten, gegebenenfalls nachbessern und dann hoffen, dass die Anwendung jetzt zum Verkauf bzw. Download freigegeben wird. Eine weitere Einschränkung, insbesondere wenn Sie eine native iPhone-Anwendung erstellen möchten: Sie müssen einen Apple-Rechner besitzen, Objective-C lernen und Apple für die Aufnahme als Entwickler bezahlen.
10
Einführung
Webanwendung Im Gegensatz zu einer nativen Anwendung braucht eine Webanwendung ein anderes Programm zur Ausführung: den Browser. Daher ist die Webanwendung auch nur so gut wie der Browser, in dem sie läuft. Funktionen, die der Browser nicht weitergeben kann, beispielsweise den Zugriff auf die Kamera eines Handys, kann demzufolge eine reine Webanwendung auch (noch) nicht nutzen. Den Vorteil, dass eine Webanwendung über einen App-Store verbreitet und sichtbar gemacht werden kann, besitzt leider auch die native Anwendung. Insbesondere wenn Sie einen kostenpflichtigen Dienst bzw. eine Anwendung anbieten möchten, müssen Sie bei einer Webanwendung eine für Sie und den zukünftigen Kunden recht umständliche Zahlungsabwicklung implementieren, während die Kreditkarte des Kunden bei iTunes und einer nativen Anwendung quasi einen Klick entfernt ist. Dennoch: Mit immer mehr Browsern, unabhängig vom Betriebssystem, die die neuesten Standards wie beispielsweise HTML5 und CSS 3 unterstützen, kann eine Webanwendung auf allen mobilen Plattformen laufen und Nutzer erreichen, egal ob diese ein iPhone, ein Google-Handy, einen Palm Pre oder ein Nokia-Telefon benutzen. Webseiten sind in der Regel viel einfacher und günstiger zu programmieren als native Programme. Viele Firmen beschäftigen bereits Heerscharen von Webentwicklern. Wie jede andere Webseite im Internet muss eine Webanwendung auch keine Genehmigungsprozedur durchlaufen, bevor sie auf einem mobilen Gerät angewendet werden kann. Der Webseitencode wird in das Internet gestellt und ist sofort weltweit auf jedem Gerät mit geeignetem Browser verfügbar. Sie müssen keine Zertifizierungsgebühr bezahlen, keine zusätzliche Software kaufen, keine komplette Entwicklungsumgebung erlernen und können Aktualisierungen Ihrer Webanwendung in Sekundenschnelle weltweit veröffentlichen.
Warum nicht beides? Dieses Buch zeigt Ihnen auf, wie Sie eine moderne mobile Webanwendung mit HTML5, CSS und JavaScript erstellen, die sich in vielen Punkten bereits im Browser wie eine richtige »native« Anwendung verhalten kann, und zeigt Ihnen gleichzeitig, wie Sie aus dieser Web App eine richtige »native« Anwendung für den App-Store und den Android Market bauen können. Das gibt Ihnen die Freiheit, Dienste zu erstellen, die von jedermann erreichbar sind. Ihnen ist aber die Chance nicht verbaut, mit der gleichen Anwendung auch in einen der App-Stores zu gelangen und dort bekannt zu werden. Idealerweise können Sie eine umfassende Webanwendung bauen, die Sie ständig (und ohne umständliche Genehmigungen) aktualisieren und ausbauen und von der Sie einen Teil der Webanwendung als native App in die verschiedenen Stores stellen können.
Einführung
11
Wer sollte das Buch lesen? Das Buch richtet sich an alle, die sich für neuartige Webanwendungen für den mobilen Markt interessieren oder sich dort bereits bewegen und aus mobilen Webseiten leistungsfähige native Anwendungen erstellen möchten. Sie finden im Buch allerhand Codebeispiele, doch richtet es sich nicht nur an Entwickler, sondern auch an Produktmanager, Designer, Vordenker, Entrepreneurs und alle anderen, die sich mit dem neuesten Trend im mobilen Bereich auseinandersetzen möchten. Entwickler werden an dem Buch auch ihre Freude haben, da es zum einen Verständnis für den mobilen Markt außerhalb der Technik vermittelt und zum anderen geballte HTML5-Beispiele auflistet, die helfen, mobile Seiten mit einer Funktionsfülle auszustatten, die bisher nur von »richtigen« Anwendungen bekannt war. Besonders tiefe Vorkenntnisse im Bereich der Programmierung setzt dieses Buch nicht voraus. Natürlich sollten Sie wissen, was ein Browser ist, wie man sich im Internet bewegt, wie man einfache Webseiten baut und woraus diese bestehen. Begriffe wie HTML, CSS und JavaScript sollten Ihnen geläufig sein – Sie müssen sie aber nicht bis ins letzte Detail verstehen, um dieses Buch zu lesen. Das Ziel dieses Buchs ist, Ihnen die verschiedenen Möglichkeiten aufzuzeigen, die heutzutage mit HTML5 auf mobilen Geräten machbar sind und, falls Sie das auch noch interessiert, wie Sie es machen können. Es vermittelt Ihnen einen Überblick über den mobilen Markt mit seinen Schwierigkeiten und Vorzügen und zeigt Ihnen auf interessante Art und Weise, wie Sie möglichst viele mobile Plattformen mit wenig Aufwand abdecken und dazu noch in den wichtigen App-Stores wie dem iPhone App Store und dem Android Market vertreten sein können. Wenn Sie noch weiter in die Welt von HTML, CSS und JavaScript vordringen oder sich tiefer mit der nativen App-Entwicklung für mobile Plattformen oder mit mobilen Konzepten beschäftigen wollen, können wir Ihnen die Lektüre der folgenden Bücher, Blogs und Podcasts empfehlen. Lesezeichen http://bit.ly/d8467s Webseitenlayout mit CSS: Das neue und sehr aktuelle CSS-Buch aus dem Franzis Verlag führt den Leser an CSS heran und berücksichtigt die neueste CSS 3-Spezifikation.
Lesezeichen http://bit.ly/doTIti HTML-Handbuch: Ganze Generationen von Webentwicklern sind mit der fabelhaften Webseite selfhtml.org aufgewachsen. Die Standardreferenz im Internet ist auch als Buch erhältlich.
Lesezeichen http://css-tricks.com/ Das englischsprachige Blog berichtet in regelmäßigen Abständen über CSS-Tipps und zeigt diese anhand von Live-Beispielen und Videos. Ein großer Teil der dort vorgestellten Themen behandelt den Einsatz von CSS in der mobilen Webentwicklung.
12
Einführung
Lesezeichen http://bit.ly/a5S2Ky JavaScript und Ajax: Wenn Sie tiefer in die JavaScript-Materie eintauchen wollen, sei Ihnen dieses Buch empfohlen. Anhand konkreter Programmierbeispiele erlernen Sie die Grundlagen bis hin zu den fortgeschrittenen Techniken von JavaScript und AJAX.
Danksagung Bevor es jetzt richtig losgeht, möchten wir uns als Autoren bei einigen Menschen bedanken, ohne die dieses Buch nicht entstanden wäre: zuallererst bei unseren Familien – insbesondere unseren Frauen Steffi und Sandra –, die von uns während der Monate vor dem Rechner nicht viel hatten und uns dennoch unterstützten und uns mit viel Espresso wach hielten. Des Weiteren geht unser Dank an: Ross Harmes, der das wunderbare Flickr-Geo-Fotobeispiel zum Buch beigesteuert hat, unserem Verleger für die aufgebrachte Geduld, die netten Kollegen vom Yahoo! Editorial Board, die ebenfalls an der Entstehung des Buchs mitarbeiteten, an Matteo Spinelli von cubiq.org, mit dem wir an einigen CSS-/JavaScript-Beispielen im Buch gearbeitet haben, und an jeden, der uns geholfen hat, die Beispiele im Buch zu testen, und die zeitlichen Möglichkeiten gegeben hat, dieses Buch zu schreiben.
Was wird benötigt? Außer dem Buch, das Sie glücklicherweise schon in Ihren Händen halten, brauchen Sie nicht viel: etwas Zeit, einen Texteditor und einen modernen Browser. Das ist wirklich die Mindestausstattung. Obwohl das ein Buch über mobile Technologien ist, brauchen Sie theoretisch nicht unbedingt ein internetfähiges Telefon. Wie gesagt, »theoretisch« – denn eigentlich würden wir Ihnen entweder ein iPhone, iPad, iPod touch oder ein Smartphone mit Android-Betriebssystem zum Testen Ihrer mobilen Webseiten oder ein anderes Mobiltelefon mit einem halbwegs guten Browser empfehlen. Wie gesagt: Alle Schritte lassen sich auch auf einem normalen Computer abbilden – ein Telefon ist nicht vonnöten! Wenn Sie aber wissen wollen, wie sich Ihre Webseite und dann auch Ihre mobile Anwendung wirklich »anfühlt«, kommen Sie um ein Handy zum Testen nicht herum. Den größten Unterschied werden Sie wahrscheinlich in der Geschwindigkeit merken: Ist auf dem Desktop-Rechner dank Hochgeschwindigkeitsinternet und Rechenpower alles superschnell, muss man beim Design und der Programmierung von mobilen Seiten sehr auf die Datengrößen achten, ansonsten kann es auf einem Telefon oft zu langwierigen und für den Benutzer sehr unschönen Ladezeiten kommen. Eine mobile Webseite können Sie zwar auf Ihrem Computer erstellen und dort auch testen. Möchten Sie jedoch die Seite auf einem Telefon testen bzw. Ihre Webseite gegebenenfalls auch ins Internet stellen, kommen Sie um etwas Speicherplatz im Internet, sogenannten Webspace, nicht herum. Eine Suche bei Google oder Yahoo! nach »WebspaceAnbieter« wird Ihnen eine ganze Liste offenbaren. Wir haben viel mit dem Anbieter 1&1 (www.1und1.de) in Deutschland gearbeitet und können ihn auch sehr empfehlen.
Einführung
13
Für eine iPhone-, iPod touch- oder iPad-Anwendung Wenn Sie aus Ihren mobilen Webseiten eine iOS-Anwendung für den App Store erstellen möchten, benötigen Sie einen Mac, also einen Rechner von Apple mit dem Mac OS X-Betriebssystem. Das ist nicht der Sonderbehandlung geschuldet, dass wir aus einer Webseite eine Anwendung generieren – selbst wenn Sie über den herkömmlichen Weg unter Benutzung von Xcode und dem iPhone SDK eine iPhone-Anwendung programmieren möchten, müssen Sie das immer auf einem Mac tun. Für eine Android-Anwendung Eine Android-Anwendung für Telefone mit diesem Betriebssystem können Sie auch auf einem PC mit Windows Betriebssystem erstellen. Alternativ können Sie einen Mac oder einen Rechner mit Linux-Betriebssystem benutzen.
Welcher Browser? Nicht nur der mobile Browsermarkt, sondern auch das Desktop-Browserangebot ist sehr reichhaltig. Da HTML5 zum Erscheinungszeitpunkt dieses Buchs wirklich eine brandneue Technologie ist, haben einige Browser noch nicht alle Bestandteile des neuen HTML-Standards integriert. Safari Sehr empfehlenswert für das Testen von mobilen Seiten ist die Installation von Safari – dem Browser aus dem Hause Apple. Apple hat in Bezug auf HTML5-Kompatibilität Standards gesetzt und auch aktiv an HTML5 und CSS mitgearbeitet. Das iPhone nutzt exakt die gleiche Safari-Technologie auf dem Telefon, wie sie auch in der Desktopversion des Browsers verwendet wird. Es kommt aber noch besser: In Safari kann man über die Programmeinstellungen ein Extramenü für Entwickler freischalten und sogar den User-Agent (quasi den Erkennungscode des Browsers) auf den eines iPhones oder iPods umschalten.
Die versteckte, aber nützliche EntwicklerOption in Safari unter Einstellungen/ Erweitert.
Gehen Sie dazu in das Safari-Menü, rufen Sie dort das Dialogfenster Einstellungen auf und klicken Sie auf Erweitert und das Zahnradsymbol. Im darauffolgenden Fenster sehen Sie die Option Menü »Entwickler« in der Menüleiste anzeigen, die Sie einfach markieren. Im Menü Entwickler finden Sie dann die entsprechenden Optionen unter
14
Einführung
dem Punkt User Agent. Aber auch andere hilfreiche Funktionen, wie beispielsweise der Safari Web Inspector (Webinformationen einblenden), auf die wir später noch zurückkommen, sind dort versteckt. Firefox Wesentlich verbreiteter als Safari ist Firefox, ein ebenfalls kostenloser Browser, der der Open-Source-Gemeinde entstammt und nach dem Internet Explorer der meistgenutzte Browser in Deutschland ist. Wie Safari ist Firefox führend in der Aktualität, wenn es um die neuen HTML5-Funktionen geht. Wenn Sie sich ausschließlich um das iPhone sorgen, sind Sie mit Safari besser bedient – falls es Ihnen aber auch um andere mobile Betriebssysteme geht, sollten Sie auf jeden Fall Firefox installieren und zum Testen benutzen. Ein weiterer Vorteil von Firefox ist die Menge an erhältlichen Erweiterungen. Was Sie im Safari-Browser über das Entwickler-Menü bewerkstelligen können, ist bei Firefox über die sogenannten Add-ons – https://addons.mozilla.org/de/firefox/ – möglich. Zwei Erweiterungen, die ich zumindest schon nennen, später aber noch näher vorstellen möchte, sind »User Agent Switcher« und »Firebug«. Safari bietet in der neuesten Version 5 sogenannte Extensions und ist somit ähnlich erweiterbar wie Firefox, doch das Angebot der Safari-Extensions ist gegenüber Firefox noch erheblich eingeschränkt. Google Chrome Die meisten Dinge, die wir über Safari und Firefox gesagt haben, gelten auch für Google Chrome: Der Browser ist in Sachen HTML5-Unterstützung up to date und besitzt wie Safari zahlreiche Funktionen, die das Entwicklerleben einfacher machen. Internet Explorer Ein Browser, der schon fast traditionell den neuesten Entwicklungen hinterherhängt, ist der Internet Explorer. Falls Sie noch die alte Version 6 des Internet Explorers besitzen, sollten Sie schnellstmöglich zur Microsoft-Seite eilen und sich die neueste Version besorgen. Viele Firmen, unter anderem Google, haben bereits die offizielle Unterstützung für diese Browserversion beendet. Für den Kontext dieses Buchs und derzeit für mobile Webentwicklung im Allgemeinen möchten wir vom Internet Explorer, auch in der Version 8, abraten. Doch auch Microsoft kann sich der Webinnovation nicht weiter verschließen: Der Internet Explorer 9 wird bereits Elemente von HTML5 verstehen und CSS 3 unterstützen.
Welcher Texteditor? Neben einem guten Browser ist ein Texteditor das wichtigste Werkzeug in der Webentwicklung. Vor dem Texteditor werden Sie die meiste Zeit verbringen, und ein guter Editor kann Ihnen helfen, den Überblick über Ihren Code zu behalten. Allerdings heißt es hier wie so oft: Weniger ist mehr. Texteditoren, die es Ihnen erlauben, den Text schön zu formatieren, wie beispielsweise Microsoft Word, erzeugen Dateien, die Sie nicht für Webseiten nutzen können.
Einführung
15
Für Windows-User gibt es eine ganze Schar an guten und auch kostenlosen Programmen, die sich hervorragend zur Webentwicklung eignen. Ich möchte den auch in Deutsch erhältlichen Editor ConTEXT (www.contexteditor.org) hervorheben, der HTML, CSS und JavaScript versteht, Sie auf Syntaxfehler aufmerksam macht und den Code übersichtlich darstellt. Für Mac-Benutzer empfiehlt sich der kostenlose Editor TextWrangler (www.barebones. com/products/textwrangler). Das Programm ist sehr stabil, hilft bei der Codeformatierung und kann Änderungen am Webseitencode auch gleich auf Ihren Webserver speichern. Mein Lieblingseditor und auch der fast aller Webentwicklerkollegen ist TextMate auf dem Mac. Das Programm ist simpel gehalten, hilft bei der Darstellung der verschiedenen HTML-Tags und lässt sich sogar in die Apple-Entwicklungsumgebung Xcode integrieren. TextMate (www.macromates.com) kann 30 Tage kostenlos getestet werden, kostet dann allerdings knapp 40 Euro. TextMate arbeitet auch vorzüglich mit dem FTP-Programm Cyberduck zusammen. Dateien können direkt aus Cyberduck heraus mit TextMate bearbeitet und direkt auf dem Webserver wieder gespeichert werden.
Welches FTP-Programm? Falls Sie Ihre Webseiten auf einem Telefon testen oder auch veröffentlichen möchten, muss Ihr frisch geschriebener Code von Ihrem Computer in das Internet, sprich auf Ihren Webserver oder Webspace gelangen. Das gelingt Ihnen in der Regel mit einem sogenannten FTP-Programm, einer Software, die Dateien von Ihrem lokalen Rechner in das Internet über das File Transfer Protocol verschieben kann. In der Regel sind FTPProgramme so aufgebaut, dass Sie auf der einen Seite ein Fenster mit dem Inhalt Ihrer Festplatte und auf der anderen Seite den Inhalt Ihres Webservers ebenfalls als Dateistruktur sehen. Dateien können dann einfach hin- und hergeschoben werden. Für Windows-Benutzer empfiehlt sich die kostenlose Software WinSCP – www.winscp .net/eng/docs/lang:de. Das Programm ähnelt sehr der Oberfläche des Windows Explorers und dürfte für die meisten Windows-Benutzer daher sehr vertraut wirken. MacAnwender, die TextWrangler benutzen, brauchen sich um keine zusätzliche Software zu sorgen, da die FTP-Funktion bereits im Programm eingebaut ist. Wer einen anderen Texteditor auf dem Mac benutzt, dem sei das Sharewareprogramm Cyberduck – www.cyberduck.de – empfohlen.
16
Einführung
Aus Cyberduck heraus können HTMLDateien direkt mit TextMate bearbeitet und unmittelbar auf den Server zurückgespeichert werden.
Upload complete – mit dem kostenlosen Programm Growl – www.growl.info – sehen Sie über eine kleine Bildschirmmeldung auf einen Blick, dass die Dateien auf den Server hochgeladen sind und Sie mit dem Testen beginnen können.
Download der Beispiele Wir haben zahlreiche Beispiele für Sie erstellt – von der einfachen HTML-Seite bis hin zu komplexeren Web Apps – und den Code im Buch veröffentlicht. Doch keine Sorge: Das Abtippen des Codes können Sie sich sparen, da alle Beispiele auf der unten aufgeführten Website zum Download zur Verfügung stehen. Download http://www.buch.cd Hier finden Sie den Code aller im Buch besprochenen Beispiele. Von hier aus lassen sich die mobilen Web Apps auch auf Ihrem iPhone, iPod, Android-Telefon oder WebOS-Palm ausprobieren.
17
Inhaltsverzeichnis 1
Mobile Designprinzipien.............................................................................. 21 1.1 Mobiles Web- und Anwendungsdesign ............................................ 22 1.1.1 Application Prototyping mit Photoshop ............................................ 23 1.1.2 Interface Builder und andere Programme ......................................... 24 1.2 iPhone-typisches Design in der Praxis.............................................. 24 1.3 Erkennung von mobilen Browsern und DesktopBrowsern ......................................................................................... 33 1.3.1 User-Agent mit JavaScript abfragen .................................................. 35 1.3.2 User-Agent mittels der .htaccess-Datei abfragen .............................. 37 1.3.3 Geltungsbereiche der .htaccess-Datei auf dem Webserver ............... 37 1.3.4 Einen falschen User-Agent vorgeben ................................................ 40 1.4 CSS- und JavaScript-Frameworks...................................................... 41 1.4.1 iWebKit 5 ......................................................................................... 41 1.4.2 Verwendete Ressourcen speichern................................................... 46 1.4.3 Form-Elemente mit iWebKit 5 ........................................................... 49 1.4.4 jQuery und jQTouch ......................................................................... 53 1.4.5 Formulare mit jQTouch ..................................................................... 63 1.4.6 jQTouch-Fehler für Radiobuttons ...................................................... 66 1.4.7 Dynamische Inhalte ......................................................................... 66 1.5 HTML und Telefonfunktionen ........................................................... 67 1.5.1 Telefonnummer benutzen ................................................................ 68 1.5.2 SMS-Anwendung aufrufen................................................................ 69 1.5.3 E-Mails versenden............................................................................ 69 1.5.4 Google Maps aufrufen...................................................................... 71 1.6 iPhone-spezifisch: Web Apps, die den Browser verbergen......................................................................................... 75 1.6.1 Startup-Bildschirm und App-Icon mit jQTouch.................................. 79 1.6.2 CSS-Gestaltung für Hoch- und Querformat ....................................... 80
2
HTML5 in der mobilen Webentwicklung ....................................................... 83 2.1 Von HTML 4 nach HTML5.................................................................. 83 2.1.1 Syntaktische Unterschiede............................................................... 83 2.1.2 Character Encoding .......................................................................... 85 2.1.3 Der !doctype html............................................................................. 85 2.2 Sprachliche Unterschiede ................................................................ 85 2.2.1 Neue APIs ........................................................................................ 87 2.2.2 Neue Input-Typen, Auto-Korrektur und Auto-Großschreibung ........... 87 2.3 Das canvas-Element......................................................................... 91 2.3.1 Formen und Pfade ............................................................................ 96 2.3.2 Bilder ............................................................................................. 101 2.3.3 Text................................................................................................ 104
18
Inhaltsverzeichnis
2.3.4 2.3.5 2.3.6 2.3.7 2.3.8 2.4 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.5 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.5.10 2.5.11 2.5.12 2.5.13 2.5.14 2.6 2.6.1 2.6.2 2.6.3 2.6.4 2.7 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 2.7.9 2.7.10 2.7.11 2.7.12 2.7.13
Füllstil, Strichstil, Linienstil ............................................................ 106 Verläufe, Muster, Schatten............................................................. 110 Transformationen........................................................................... 114 Anordnung ..................................................................................... 116 Diagramme mit Flot ........................................................................ 117 Audio und Video ............................................................................ 122 Audiowiedergabe........................................................................... 123 MIME-Types ................................................................................... 125 Aufbau einer Videodatei ................................................................ 126 Videocodecs .................................................................................. 127 Fehlerbehandlung.......................................................................... 135 Videoimplementierung mittels JavaScript-API................................. 137 2-pass Encoding – was ist das?...................................................... 140 Geolocation-API ............................................................................. 148 Privatsphäre und Sicherheit ........................................................... 149 Feature Detection: Geolocation-API ................................................ 152 Arten der Positionsbestimmung ..................................................... 155 Google Maps-API............................................................................ 155 One-Shot-Positionsanfragen .......................................................... 156 Ortungsmethoden.......................................................................... 160 PositionOptions genauer betrachtet............................................... 162 Error-Callbacks............................................................................... 166 WatchPosition – ständige Positionsupdates .................................. 167 Reverse Geocoding mit Google Maps-API ....................................... 172 Georeferenzierte Fotos von Flickr einbinden ................................... 176 Weitere georelevante API-Methoden bei Flickr................................ 184 Geolocation mit jQTouch einbinden ............................................... 185 Zusammenfassung und Ausblick ................................................... 187 Web Storage .................................................................................. 188 Feature Detection: Darf Web Storage benutzt werden? ................... 189 sessionStorage und localStorage ................................................... 190 Beispiele zu localStorage und sessionStorage ............................... 192 Storage-Event ................................................................................ 199 Web SQL Database ........................................................................ 202 Grundlagen relationaler Datenbanken............................................ 203 SQL-Basics..................................................................................... 203 Transaktionen ................................................................................ 206 Database-API ................................................................................. 206 Neue Datenbank in den iPhone-Einstellungen................................ 207 Daten speichern............................................................................. 209 SQL Injection ................................................................................. 210 Daten aktualisieren........................................................................ 211 Datenbank-Queries ........................................................................ 212 Daten löschen................................................................................ 213 Schemamigration........................................................................... 213 Web-SQL-Database: Notes-Beispielanwendung ............................. 218 Datenbanken im Safari Web Inspector und in Google Chrome ........ 226
Inhaltsverzeichnis
2.8 2.8.1 2.8.2 2.8.3 2.8.4 2.8.5 2.9
19
Offline Web Applications................................................................ 227 Grundlagen der Cache-Manifestdatei ............................................. 227 Feststellen, ob der Browser online ist............................................. 229 Online-Whitelist und Fallback-Sektion ........................................... 229 Dynamische Erzeugung des Cache-Manifests................................. 231 Die ApplicationCache-API............................................................... 231 Zusammenfassung......................................................................... 237
3
Native Anwendungen erstellen .................................................................. 239 3.1 Titanium vs. PhoneGap .................................................................. 239 3.2 SDKs, IDEs und ADTs...................................................................... 241 3.2.1 Entwicklungsumgebung für iOS-Entwicklung einrichten ................. 241 3.2.2 Entwicklungsumgebung für Android-Entwicklung einrichten .......... 243 3.2.3 PhoneGap installieren.................................................................... 248 3.3 iOS-Apps mit PhoneGap entwickeln ............................................... 259 3.3.1 Eine Anwendung für iOS erstellen .................................................. 259 3.3.2 Einstellungen in der Info.plist-Datei ............................................... 273 3.3.3 Mit PhoneGap und Xcode direkt auf einem iOS-Gerät testen .......... 279 3.3.4 Native iOS-Systemfunktionen in PhoneGap einbinden ................... 283 3.3.5 Lokalisierte Button-Bezeichnungen................................................ 288 3.3.6 Ladeanzeige in der Statusleiste ..................................................... 296 3.3.7 Adressbucheinträge neu anlegen und abrufen ............................... 296 3.3.8 Kamera und Fotobibliothek ............................................................ 304 3.3.9 Geolocation ................................................................................... 308 3.3.10 Bewegungssensoren...................................................................... 311 3.3.11 iPad-Apps mit PhoneGap erstellen ................................................. 314 3.4 Android Apps mit PhoneGap entwickeln ........................................ 319 3.4.1 Mit PhoneGap und Eclipse direkt auf einem Android-Gerät testen ............................................................................................ 322 3.4.2 Eigene Programmsymbole erstellen und verwenden....................... 323 3.4.3 Einstellungen in der Datei AndroidManifest.xml ............................. 326 3.4.4 Android-App mit Menüfunktionen versehen ................................... 327 3.4.5 Original-Android-Grafiken in Ihren Projekten verwenden ................ 330 3.4.6 Native Android-Systemfunktionen integrieren ................................ 330 3.4.7 Android und Kameraanwendungen ................................................ 332 3.4.8 Zusammenfassung......................................................................... 334
4
Webanwendungen und native Apps veröffentlichen ................................... 335 4.1 Apple Web Apps-Katalog................................................................ 335 4.1.1 Andere Vertriebsmöglichkeiten für Web Apps................................. 337 4.2 iTunes App Store............................................................................ 338 4.3 Android Market .............................................................................. 347 4.3.1 App an Betatester schicken oder außerhalb des Android Market vertreiben ...................................................................................... 352 4.3.2 App im Android Market veröffentlichen .......................................... 353 4.3.3 App im Android Market verkaufen .................................................. 354 Stichwortverzeichnis ................................................................................. 357
21
1
Mobile Designprinzipien
Bevor wir uns an das Programmieren einer mobilen Webseite machen, möchten wir auf einige Designgrundlagen für das mobile Anwendungs- und Webdesign aufmerksam machen. Das Design einer mobilen Seite oder Anwendung kann in vielen Punkten als komplexer als das Webdesign einer Desktopseite angesehen werden. Auf folgende Herausforderungen werden Sie stoßen, wenn Sie mobile Programme erstellen möchten: •
Der Bildschirm ist wesentlich kleiner.
•
Der Benutzer bedient die Anwendung mit dem Finger, nicht mit der Maus.
•
Die Texteingabe ist selbst bei High-End-Telefonen immer noch keine Freude.
•
Der Benutzer hat unterwegs andere Anforderungen an eine Anwendung oder Webseite als zu Hause oder bei der Arbeit am PC.
•
Trotz UMTS und anderer Technologien ist das mobile Internet nicht beständig schnell, ein Nutzer kann sogar in Gebiete ohne Empfang kommen.
Um diese Probleme so gut wie möglich zu lösen, sollten Sie bei dem Anwendungsdesign einer mobilen Anwendung auf folgende Dinge achten: •
Machen Sie sich am Anfang Ihres Konzepts klar, was Ihr zukünftiger Benutzer für Vorteile hat, wenn er Ihre Anwendung unterwegs benutzt. Was könnte die Hauptnutzung, der hauptsächliche sogenannte »Use Case«, Ihrer Anwendung sein?
•
Eine mobile Anwendung wird wahrscheinlich nicht erfolgreich sein, wenn sie unterwegs keinen Sinn ergibt oder die Funktionen, die für die Benutzung unterwegs wenig sinnvoll sind, gegenüber anderen Funktionen heraushebt.
•
Nicht alle Inhalte eignen sich für die mobile Nutzung: Große Grafiken oder extrem lange Texte sind ungeeignet, verursachen lange Ladezeiten oder passen nicht in das Design für kleine Bildschirme. Versuchen Sie, angepasste Inhalte zu verwenden.
•
Wenn nicht der falsche Use Case oder Designansatz den Erfolg einer mobilen Anwendung »killt«, dann ist es die fehlende Geschwindigkeit. Der mobile Benutzer ist in der Regel viel ungeduldiger und erwartet – insbesondere von einer Seite oder Anwendung, die für die mobile Nutzung optimiert ist – auch eine optimierte Geschwindigkeit.
•
Versuchen Sie, die Texteingabe so weit wie möglich zu minimieren. An jeder Stelle, an der der Benutzer Ihrer mobilen Anwendung längere Informationen eingeben muss, ist Scheitern programmiert. Zwar bietet insbesondere das iPhone eine für mobile Geräte recht komfortable Eingabemethode, dennoch wird ein Großteil Ihrer Benutzer Eingabefelder so weit wie möglich meiden.
•
Falls Sie nicht um bestimmte Texteingabefelder herumkommen, versuchen Sie nach Möglichkeit, diese schon vorher sinnvoll auszufüllen. In diesem Fall hat der Benutzer
22
Kapitel 1 – Mobile Designprinzipien
immer noch die Chance, den vorgeschlagenen Inhalt zu verändern oder zu löschen, kann ihn aber auch einfach ohne Texteingabe akzeptieren, wenn er mit dem Vorschlag einverstanden ist. •
Vermeiden Sie komplexe Formulare mit Texteingabe. Die meisten TouchscreenTelefone blenden eine Bildschirmtastatur ein, die einen Großteil des Bildschirms verdeckt. Unter Umständen sehen Sie gar nicht mehr, was Sie eingeben sollen, da sich die Bildschirmtastatur über die Felder gelegt und der Fokus sich verschoben hat.
•
Mittels HTML5 können Sie glücklicherweise wesentlich flexiblere Texteingabefelder definieren. Mehr dazu lesen Sie im Abschnitt 2.2.2 »Neue Input-Typen, AutoKorrektur und Auto-Großschreibung«.
•
Lassen Sie sich nicht von der Traumvorstellung des mobilen Nutzers verführen! Er ist ein ganz normaler Anwender, nicht unbedingt technisch versiert, wenig interessiert am »Entdecken« von Funktionen und Bereichen einer mobilen Anwendung, und er kommt meistens auch ohne Superfinger mit Stylus-Durchmesser daher. Gestalten Sie daher Ihre Schaltflächen auch für etwas dickere Finger.
Auch wenn sich die gerade aufgeführten Punkte nach einer Reihe von Einschränkungen anhören und den Spaß am Anwendungsdesign verderben, so bieten mobile Anwendungen auch einzigartige Möglichkeiten: •
Der Benutzer kann Ihre mobile Anwendung oder Webseite immer bei sich tragen. Dazu ist Ihre Kreation auf dem Medium und dem Gerät da, mit dem der Benutzer einen Großteil seiner Kommunikation abwickelt. Bieten Sie in Ihrer Anwendung oder Webseite Schnittstellen zu den Telefonfunktionen an, wenn es Sinn ergibt. Aus einer Webseite und natürlich auch aus einer Anwendung heraus können Sie Telefonanrufe initiieren, Inhalte per E-Mail verschicken oder sie im Internet direkt vom Handy heraus verbreiten.
•
Insbesondere HTML5 bringt mit den Location-Funktionen die aktuelle Position des Benutzers zu Ihnen. Wenn Sie wissen, wo auf der Welt sich Ihr Nutzer befindet, können Sie passgenaue Dienste anbieten. Allein durch die Verfügbarkeit dieser Information lassen sich Tausende mobilspezifische Anwendungen bauen.
•
Mit den Offlinekapazitäten von HTML5 haben Sie die Chance, mobile Anwendungen zu konzipieren, die auch ohne Internetverbindung auskommen oder kurze Verbindungsausfälle, wie sie mit einem Telefon schon mal vorkommen, ganz geschickt zu überspielen.
•
JavaScript und HTML5 bieten Ihnen unglaubliche Möglichkeiten, nicht immer eine ganze Seite, sondern nur bestimmte Teile der Seite neu zu laden. Machen Sie davon Gebrauch – wenn es sinnvoll ist!
1.1
Mobiles Web- und Anwendungsdesign
Da das iPhone ohne Frage die mobile Welt verändert und Standards im mobilen Webdesign gesetzt hat, möchten wir im nächsten Abschnitt auf bestimmte Charakteristiken im iPhone-Webdesign eingehen und sie vorstellen. Für alle Beispiele im Buch werden
1.1 Mobiles Web- und Anwendungsdesign
23
wir ein iPhone-typisches Standarddesign verwenden. Sie werden lernen, wie Sie dieses Design durch Editieren der Cascading Style Sheets verändern und wie Sie mit nur wenigen Zeilen Code Ihrer Anwendung oder Webseite ein iPhone-Look geben können.
1.1.1
Application Prototyping mit Photoshop
Bevor Sie mit dem Programmieren einer iPhone-Webanwendung beginnen, ist es ratsam, sich die verschiedenen Bildschirme, die ein Benutzer sehen und durch die er durchnavigieren soll, zu überlegen und aufzuzeichnen. Am Anfang landen diese FlowÜberlegungen meistens auf Skizzenpapier, einer Serviette oder auf dem Whiteboard. Wenn der grobe Flow allerdings steht, empfiehlt es sich gerade bei iPhone- oder iPod touch-Anwendungen – in denen es zu einem überdurchschnittlich großen Teil um die User-Experience geht –, die einzelnen Bildschirme detaillierter zu gestalten und aufzuzeichnen. Diese Art von »Application Prototyping« ist ein wichtiger Schritt in der Software- und Webentwicklung und hilft beim Entdecken von Problemen im Anwendungsdesign. Falls Sie Photoshop besitzen und sich mit dem Programm auskennen, können Sie vorgefertigte Bibliotheken mit den verschiedenen iPhone-typischen Elementen wie Titelleisten, Buttons, Eingabefeldern, Tastatur etc. laden und in Photoshop zu der idealen Oberfläche Ihrer Anwendung anordnen. Lesezeichen http://bit.ly/Bvn5o Besitzen Sie Photoshop und kennen das Programm bereits, können Sie vorgefertigte Bibliotheken mit den verschiedenen iPhone-typischen Elementen laden und wunschgemäß anordnen.
Lesezeichen http://bit.ly/89DYC4 Wenn Sie sich speziell für eine iPad-Anwendung interessieren, gibt es unter dieser Adresse eine 24 MByte große Photoshop-Datei mit allen relevanten iPad-Elementen.
Auch für diejenigen, die sich speziell für Android-Webanwendungen oder mittels PhoneGap auch für Android Apps interessieren, gibt es zahlreiche Photoshop-Vorlagen im Internet. Lesezeichen http://bit.ly/cO0aLH Eine der umfassendsten Vorlagen hat Vladimir Grishin auf seiner Webseite zum kostenlosen Download zur Verfügung gestellt.
24 1.1.2
Kapitel 1 – Mobile Designprinzipien
Interface Builder und andere Programme
Falls Sie einen Mac Ihr Eigen nennen, können Sie auch das offizielle iPhone SDK herunterladen (mehr dazu am Ende des Buchs) und die Software Interface Builder benutzen. Besitzen Sie weder Photoshop noch einen Mac, gibt es immer noch zahlreiche Möglichkeiten, Flows visuell zu erstellen. Diese werden keine so detaillierte Darstellung der Benutzeroberfläche bieten, können aber immer noch jede Menge Probleme beim Userflow aufzeigen. Persönlich verwende ich auf dem Mac die Apple-Software Keynote sehr gern, auf dem PC greife ich auf PowerPoint oder Microsoft Visio zurück. Mit jedem iOS SDK kommt auch das Programm Dashcode, das sogar aus der gestalteten Oberfläche HTML, CSS und JavaScript generiert. Obwohl sich mit Dashcode komfortabel UI-Elemente platzieren und ausprobieren lassen, haben wir auf eine nähere Vorstellung verzichtet, da wir glauben, dass der beste Code immer noch der ist, den man selbst geschrieben hat. Auch nutzt Dashcode viele der mit HTML5 gegebenen Möglichkeiten nicht aus und generiert Code, der zu Problemen mit den erhältlichen mobilen Frameworks führen kann. Ist das der Fall, lassen sich daraus keine nativen Apps erstellen. Trotzdem sollten Sie sich das Programm, wenn Sie einen Mac haben, einmal ansehen. Im hinteren Teil des Buchs beschreiben wir die Installation des iOS SDK.
1.2
iPhone-typisches Design in der Praxis
Um das Design einer Web App wirklich zu verstehen, werden wir in diesem Abschnitt eine normale Webseite, die für die Darstellung auf einem Desktopbildschirm optimiert ist, in eine mobile Webseite umwandeln. Ziel ist es, die HTML-Struktur der Seite unangetastet zu lassen, da, wie bereits gelernt, der HTML-Code idealerweise den Inhalt einer Seite, aber nicht deren Aussehen bestimmt. Das Look & Feel einer Seite wird durch CSS definiert, und dieses kann sich in der Darstellung auf einem PC drastisch von der auf einem mobilen Gerät unterscheiden. Im folgenden Beispiel wird eine Seite für einen Autohändler erstellt. Im Kopfbereich des HTML-Codes wird auf drei verschiedene CSS-Dateien verwiesen. Die erste CSS-Datei computer.css bestimmt die Darstellung auf allen Geräten, die eine Bildschirmgröße von mehr als 961 Pixeln aufweisen. Die zweite Datei ist die für unsere Umgestaltung relevante Datei und nennt sich mobile.css. Die dort befindlichen CSS-Definitionen werden bei allen Geräten verwendet, die nur aus einem Bildschirm bestehen und eine maximale Bildschirmbreite von 960 Bildpunkten besitzen. Der dritte CSS-Verweis ist für die Druckausgabe gedacht, und der darunterliegende Eintrag ist die bereits vorher im Buch beschriebene Sonderlösung für Microsofts Internet Explorer. Warum 960 Bildpunkte? Während man früher nur eine maximale Bildschirmgröße von 480 Bildpunkten angeben musste, hat sich das mit den neuen Android-Geräten und auch dem iPhone 4 geändert. Würden Sie im unteren Beispiel nur den Wert 480 angeben, erhielten Sie theoretisch eine mobile Seite auf einem älteren iPhone 3G und die volle Desktopseite auf einem iPhone 4. Eine User-Experience, die Sie mit Sicherheit nicht möchten.
1.2 iPhone-typisches Design in der Praxis
25
Praktisch funktioniert die Angabe von 480 Bildpunkten allerdings noch mit dem iPhone 4, da der Retina-Bildschirm intern die doppelte Pixelanzahl berechnet. Sie könnten daher ein iPhone 4 sogar mit folgender Zeile erkennen und spezielle CSSDefinitionen zuweisen:
Sie werden etwas weiter unten im Buch noch bessere Möglichkeiten kennenlernen, um ein iOS- oder Android-Gerät von normalen Computern zu unterscheiden. Sie sollten wissen, dass wir pro Ausgabemedium unterschiedliches CSS zuweisen können, allerdings gibt es in der Praxis wesentlich verlässlichere Wege dazu. Die Seite untergliedert sich in vier Hauptbereiche: den Kopfbereich mit dem Namen des Autohändlers, die Navigation, den eigentlichen Inhalt und die Kontaktadresse, die im Fußbereich der Webseite steht. Alle Bereiche sind deutlich als einzelne div-Bereiche gekennzeichnet. Die Stylesheets in der Datei computer.css bezeichnen nicht nur die Schriftgröße oder die Hintergrundfarbe, sondern bestimmen auch die Anordnung der einzelnen Hauptteile. Was früher oft von unsichtbaren Tabellen übernommen wurde, lässt sich einfach und wesentlich präziser mit div-Bereichen und CSS übernehmen. Oldtimer Spiering Oldtimer Spiering Spitzen Oldtimer von VW und Porsche
Wir führen und reparieren Old und Youngtimer der Marken VW und Porsche.
- Aktuelle Angebote
- Unsere VWs
- Unsere Porsche
- Preisrechner
- Reparaturen
26
Kapitel 1 – Mobile Designprinzipien
Wir importieren auch aus Kalifornien!
Neu im Angebot: Volkswagen Karmann Ghia
Oldtimer Spiering
Beispielgasse 1, 12345 Bad Beispielstadt
Mit den entsprechenden CSS-Definitionen für die Desktop-Ausgabe (computer.css) wird der Beispielcode im Safari-Browser auf dem Mac (und auf dem PC) wie folgt dargestellt:
Bild 1.1: Darstellung des Beispiels als Desktopwebseite.
Alle neuen Smartphones, allen voran natürlich das iPhone, Handys mit dem AndroidBetriebssystem oder Handys von Palm mit dem WebOS-System besitzen bereits fantastische Browser, die die PC-Webseite ohne Probleme auch ohne handyspezifisches CSS wiedergeben können. Nehmen wir also an, dass wir die gleichen CSS-Definitionen wie in computer.css auch in mobile.css abgespeichert haben, dann sieht unsere Seite auf einem iPhone wie folgt aus:
1.2 iPhone-typisches Design in der Praxis
27
Bild 1.2: Darstellung des Beispiels auf einem iPhone ohne mobilspezifisches CSS.
Nicht schlecht, oder? Die Seite ist identisch mit der Seite auf dem PC, bringt aber auch einige Probleme mit sich. Die Links in der Navigation sind kaum sichtbar und, da das iPhone und viele andere moderne Handys mit dem Finger bedient werden, kaum verlässlich selektierbar. Weiterhin ist die kleine Schrift schlecht zu lesen, insbesondere wenn die gesamte Seite dargestellt wird. Man kann natürlich den Zoom benutzen, doch dann muss man nicht nur vertikal, sondern auch horizontal scrollen, was den Spaß am Lesen der Seite verdirbt. Um diese Desktop-Seite nun in eine mobile Webseite zu verwandeln, bedarf sie nur ein bisschen CSS und einer HTML-Änderung. Zwar hatten wir versprochen, dass der HTML-Code nicht angefasst werden muss, doch wird der folgende Befehl von allen nicht mobilen Browsern ignoriert und spielt nur für mobile Browser eine entscheidende Rolle: <meta name "viewport" content "width device width; initial scale 1.0; maximum scale 1.0; user scalable 0;" />
Der Viewport eines Smartphones ist der Bereich, in dem eine Webanwendung sichtbar laufen kann. Der Viewport einer PC-Webseite ist in der Regel die Größe des Browserfensters, das auch vom Benutzer vergrößert oder verkleinert werden kann. Beim iPhone ist der Viewport wesentlich kleiner und auf die Bildschirmgröße des iPhones minus des Bereichs für die Zeit- und Batterieanzeige, für die URL-Leiste und die untere Funktionsleiste reduziert. Den Viewport kann man am besten mit einem Stück Papier vergleichen, das über einem Buch liegt und es abdeckt. Wenn Sie aus diesem Stück Papier ein Viereck ausschneiden und es über das Buch schieben, ist dies ein ähnlicher Mechanismus wie der Viewport eines mobilen Geräts. Wenn Sie eine Webseite auf einem mobilen Gerät scrollen, wollen Sie etwas unbedingt vermeiden: einen horizontalen Scroll. Bricht Ihre Webseite beim Hoch- und Runterscrollen jedes Mal links oder rechts aus und verdeckt dabei Inhalte, ist sie schwer zu bedienen und wird nur wenig Liebhaber finden. Die Definition des Viewports mit dem oben genannten meta-Tag bewirkt, dass der Viewport exakt auf die Bildschirmbreite beschränkt wird.
28
Kapitel 1 – Mobile Designprinzipien
Sie sehen hier, dass wir mit content "width device-width..." keinen exakten Zahlenwert angeben, da sich die Breite des Viewports beispielsweise ändert, wenn Sie das iPhone drehen und der Webseiteninhalt im Querformat angezeigt wird. Die weiteren Parameter beschreiben, dass die Webseite in der Originalgröße angezeigt wird und der Benutzer die Darstellung selbst nicht skalieren kann: user-scalable 0. Allein durch diese eine Zeile verbessert sich die Lesbarkeit der Webseite enorm, da Safari nicht versucht, die Seite in der kompletten Breite darzustellen, und eine besonders kleine Zoomstufe für die Seite wählt.
Bild 1.3: Webseite nach Verwendung des Viewport-meta-Tags.
Die Seite berücksichtigt immer noch die in der CSS-Definition festgelegten Seitenabstände, wird aber nicht mehr automatisch »klein gezoomt« und lässt sich nicht mehr seitlich, sondern nur noch nach oben und nach unten verschieben. Dennoch ist das Design noch meilenweit von dem einer iPhone-Webanwendung entfernt. Aus diesem Grund geht es jetzt an das CSS in der Datei mobile.css. In fast allen iPhone-Webanwendungen wird die Titelleiste von den mitgelieferten Anwendungen nachgebaut. Beispielsweise nutzt die iPod-Anwendung auf dem iPhone die Titelleiste zur Hauptnavigation. Navigation im Kopfbereich Der Nachbau der Kopfleiste als Navigationsleiste ist vor allem sinnvoll, da Safari nach dem Laden einer Webseite oder unter bestimmten Umständen (dazu später mehr) die URL-Eingabeleiste ausblendet und nur noch die Kopfleiste als erstes Element sichtbar bleibt. Dieses Verhalten finden Sie übrigens nicht nur im mobilen Safari-Browser, sondern auch bei seinen Kollegen auf WebOS-Geräten von Palm, den Android-Handys und anderen Browserimplementierungen. Mit dem folgenden CSS wird noch keine Schaltfläche in den Kopfbereich implementiert, allerdings wird die Titelleiste nach der CSS-Behandlung schon wesentlich mehr nach dem iPhone aussehen. Zuerst wird der gesamte Seitenhintergrund auf einen Grauton gesetzt. Als Schriftart nehmen wir die Standardschriftart des iPhones, Helvetica (font-family: Helvetica) in einem sehr dunklen Grauton (color: #222;).
1.2 iPhone-typisches Design in der Praxis
29
body { background color: #ddd; color: #222; font family: Helvetica; font size: 14px; margin: 0; padding: 0; }
Als Titelzeile soll nicht der gesamte Kopfbereich, wie er in div id "kopfbereich" definiert wurde, sondern nur die erste Zeile mit dem HTML-Tag h1 verwendet werden. Das CSS, das das Aussehen der Titelzeile definiert, wird demnach nur auf das div #kopfbereich und das HTML-Tag h1 beschränkt: #kopfbereich h1 { background color: #fcc97d; border bottom: 1px solid #666; color: #222; display: block; font size: 20px; font weight: bold; padding: 10px 0; text align: center; text decoration: none; text shadow: 0px 1px 0px #fff; }
Mit der Farbdefinition background-color: #fcc97d; wird ein orangefarbener Hintergrund gesetzt, der sich auch auf der PC-Seite fand. Falls Ihnen mehr nach dem Apple-Grau der iPod-Anwendung ist, setzen Sie den Wert auf #98a8bf. Die CSS-Definition text-shadow: 0px 1px 0px #fff; versieht die dunkelgraue Schrift in der Kopfzeile mit einem kleinen, weißen Schatten. Damit auch die anderen Inhalte im Kopfbereich-div ordentlich dargestellt werden, auch wenn sie nicht zur Titelzeile gehören, fügen wir noch folgendes CSS ein: #kopfbereich h2, p { margin left: 12px; margin right: 10px; }
Die Titelzeile erscheint jetzt schon als eigenständiger Block, allerdings fehlt noch der für das iPhone typische Farbverlauf. Dieser kann entweder als Bild eingebunden oder viel besser automatisch vom Browser über die folgende Anweisung generiert werden: #kopfbereich h1 { background image: webkit gradient(linear, left top, left bottom, from(#fcc97d), to(#fcaf3b)); }
30
Kapitel 1 – Mobile Designprinzipien
Bild 1.4: Fertig ist eine iPhonetypische Kopfzeile in Orange.
Die Farbangaben bestimmen einen Verlauf von einem hellen Orange in ein dunkles Orange. Wollen Sie die iPhone-Grautöne verwenden, ändern Sie in der CSS-Definition für #kopfbereich h1 die folgenden Zeilen: background image: webkit gradient(linear, left top, left bottom, from(#b2bcc8), to(#76859a)); text shadow: 0px 1px 0px #222; color: #fff;
Diese Angaben versehen die Kopfleiste mit einem grauen Farbverlauf, einer weißen Schrift und einem umgekehrten dunklen Schatten.
Bild 1.5: Eine Kopfzeile im iPhonetypischen Grau mit weißer Schrift.
Ein wirklicher Problembereich war die Navigationsspalte, als die Webseite mit der PCFormatierung auf dem iPhone angezeigt wurde. Die Links waren zu klein und somit schwer anzutippen und sahen auch überhaupt nicht nach den gewohnten Linkflächen einer iPhone-Webanwendung aus. Mit den folgenden CSS-Definitionen werden die Links, die als li-Elemente aufgelistet waren, in große, schöne Schaltflächen umgewandelt. Dabei wird eine weiße Hintergrundfarbe für die Schaltflächen benutzt, die mit einem 1 Pixel starken Rahmen umgeben sind: div#navigation ul { list style: none; margin: 10px; padding: 0; } div#navigation ul li a { background color: #FFFFFF; border: 1px solid #d9d9d9; color: #222222; display: block; font size: 17px; font weight: bold; margin bottom: 1px; padding: 12px 10px; text decoration: none; }
1.2 iPhone-typisches Design in der Praxis
31
Was für die Titelzeile der Farbverlauf ist, sind für die Schaltflächen die runden Ecken. Die folgenden CSS-Zeilen fügen genau diese Rundungen an den jeweiligen Ecken mit einem Radius von 10px der Liste hinzu: #navigation ul li:first child a{ webkit border top right radius: 10px; webkit border top left radius: 10px; } #navigation ul li:last child a{ webkit border bottom right radius: 10px; webkit border bottom left radius: 10px; }
Das Ergebnis kann sich nach dem Hinzufügen dieser wenigen CSS-Zeilen bereits sehen lassen und dürfte kaum noch an eine normale PC-Seite erinnern, sondern vielmehr an eine schicke iPhone-Webanwendung:
Bild 1.6: Webseite mit iPhone-typischer Kopfzeile und Navigationselementen.
Jetzt ist nur noch der restliche Inhalt in die passende Form zu bringen, was bedeutet, dass sich der Inhalt an den rechten und linken Abständen orientieren muss: #inhalt { margin left: 12px; margin right: 10px; }
Beim angezeigten Bild haben wir etwas geschummelt und das Bild bereits auf eine Breite von 298 Bildpunkten zugeschnitten, sodass es perfekt in die Seite passt. Warum aber 298 Bildpunkte? 320 Bildpunkte ist die Breite des iPhone-Bildschirms. Wenn Sie 12 Punkte am linken Rand (margin-left: 12px;) und 10 Punkte am rechten Rand (margin-right: 10px;) abziehen, ergibt sich die Bildbreite von 298 Pixeln. Was man beim Bild noch hinzufügen kann, sind ähnlich wie bei den Navigationselementen die Abrundungen an den Ecken. Man sieht diese Behandlung von Bildern beispielsweise im Adressbuch des iPhones, wo ein dünner Rahmen um das Kontaktfoto gezeichnet ist und leichte Abrundungen an den Ecken vorgenommen wurden. Die folgende CSS-Definition verändert genau dies am angezeigten Bild:
32
Kapitel 1 – Mobile Designprinzipien
#inhalt img { border: 1px solid #222222; webkit border radius: 5px; }
Die Fußzeile, also das Adressfeld des Autohändlers, soll ähnlich wie der Kopfbereich aussehen, jedoch eine Linie am oberen Rand erhalten, die Schrift soll kleiner und ohne Schatten sowie zentriert ausgerichtet sein. Demzufolge muss der Datei mobile.css noch folgende CSS-Definition hinzugefügt werden: #kontakt { background color: #fcc97d; border top: 1px solid #666; color: #222; display: block; font size: 10px; font weight: bold; padding: 5px 0; text align: center; text decoration: center; }
Nach diesen eigentlich wenigen Zeilen CSS haben Sie eine Weboberfläche, die für das iPhone und andere Touchscreen-Handys optimiert ist. Dabei musste, bis auf eine zusätzliche Zeile, der HTML-Code nicht geändert werden, und die zwei komplett unterschiedlichen Designs wurden einfach nur von einigen Zeilen CSS definiert.
Bild 1.7: Fertig – die Webseite sieht jetzt nach einer iPhone-Webanwendung aus.
1.3 Erkennung von mobilen Browsern und Desktop-Browsern
33
Sie wissen nun, dass das Aussehen einer Webseite getrennt vom HTML-Code definiert werden kann, und haben erfahren, wie man mit ein paar CSS-Kenntnissen eine iPhoneSeite gestalten kann. Natürlich sind wir in diesem Buch nicht die Ersten, die mit einer Reihe von CSS-Definitionen versucht haben, Webseiten für das iPhone und andere mobile Plattformen zu optimieren. Es gibt bereits eine ganze Reihe von vorgefertigten CSS- und JavaScript-Frameworks, die Sie einfach herunterladen und in Ihren Projekten verwenden können.
1.3
Erkennung von mobilen Browsern und DesktopBrowsern
Sie haben es vielleicht schon geahnt, aber die Unterscheidung anhand der folgenden Codezeilen, ob ein mobiles Gerät oder ein Desktop-Browser die Seite aufruft, ist relativ unzuverlässig:
Diese Art der Unterscheidung war früher relevant, als Mobiltelefone noch nicht die Bildschirmauflösungen von PC-Monitoren oder Laptops hatten, doch jetzt verschwindet diese Grenze immer mehr. Wir haben aber mit dem Beispiel noch etwas anderes bezweckt: Wir wollten Ihnen zeigen, dass Inhalt und Aussehen einer Seite komplett unabhängig voneinander gestaltet werden können und dass Sie die Möglichkeit besitzen, einfach über CSS eine iPhone-Version Ihrer PC-Seite zu erstellen, ohne dass Sie auch nur eine Zeile der HTML-Befehle ändern müssen. In der Praxis würden wir von dieser Methode abraten, es sei denn, Sie haben nur eine kleine, gut kontrollierbare Desktop-Seite. Alle größeren Webanbieter haben einen separaten Seitencode für Desktop-Webseite und Mobilseite. Dies sehen Sie allein schon daran, dass mobile Webseiten oft sogar unter einer eigenen Domain (beispielsweise m.spiegel.de) laufen. Die meisten Webseitenanbieter verweisen automatisch auf die mobile Seite, wenn ein iPhone-Benutzer die Desktop-Seite ansteuert. Auch wenn Sie in Ihrem iPhone www.spiegel.de eingeben, landen Sie wenige Augenblicke später auf m.spiegel.de. Um eine derartige Logik in der eigenen Webseite zu implementieren, bedarf es der Kenntnis des User-Agent-Headers. Neben den auf einer Webseite sichtbaren Daten wird noch eine Reihe unsichtbarer Daten, die sogenannten HTTP-Header, ausgetauscht. Dies passiert immer dann, wenn Sie einen Webserver, beispielsweise durch die Eingabe einer Webadresse, von Ihrem Browser aufrufen. Die Webseite www.xhaus.com/headers zeigt Ihnen, welche Informationen im HTTPHeader übertragen werden. Testen Sie es einmal von Ihrem Telefon oder Ihrem Desktop-Browser aus.
34
Kapitel 1 – Mobile Designprinzipien
Bild 1.8: Anzeige der übertragenen Informationen im HTTP-Header.
Diese HTTP-Header helfen dem Webserver, die richtigen Daten auszuliefern, da sie wichtige Informationen wie … •
… die Spracheinstellung des Browsers mitteilen: Accept-Language.
•
… die URL übertragen, von der aus der Benutzer Ihre Seite erreicht hat: Referer.
•
… den Browser der Benutzer übermittelt: User-Agent.
In diesen sogenannten User-Agents wird beispielsweise für den von mir gerade verwendeten Browser folgende Zeichenfolge angezeigt: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10 6 3; en us) AppleWebKit/531.22.7 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7
Neben der Information, dass ein Apple-Computer mit Mac OS X 10.6.3 die Seite aufgerufen hat, wird auch deutlich, dass der Safari-Browser hinter dem Aufruf steckt. User-Agent-Zeichenfolgen für mobile Browser iPhone 4
Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; de-de) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.05 Mobile/8A293 Safari/6531.22.7
iPod touch
Mozilla/5.0 (iPod; U; CPU iPhone OS 4_0 like Mac OS X; de-de) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7
Google Nexus One
Mozilla/5.0 (Linux; U; Android 2.2; de-de; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1
iPad
Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; de-de) AppleWebKit/531. 21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B334b Safari/531.21.10
Palm Pre
Mozilla/5.0 (webOS/1.0; U; de-DE) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/1.0 Safari/525.27.1 Pre/1.0
1.3 Erkennung von mobilen Browsern und Desktop-Browsern
35
In jedem dieser User-Agents sehen Sie, welches Gerät, welcher Browser und welches Betriebssystem vom Benutzer verwendet wird. Anhand dieser Informationen ist es einfach, die richtige Version der Webseite (mobil oder nicht mobil) auszuliefern. Dazu gibt es verschiedene Möglichkeiten:
1.3.1
User-Agent mit JavaScript abfragen
Die User-Agent-Zeichenfolge ist im JavaScript-Objekt navigator.userAgent enthalten. Die folgende kleine Webseite demonstriert, wie einfach es ist, den User-Agent eines Benutzers zu erhalten und anzuzeigen: User Agent Bestimmung <meta name "layout" content "webkit" /> <meta content "minimum scale 1.0, width device width, maximum scale 0.6667, user scalable no" name "viewport" /> <meta name "layout" content "webkit" /> Ihr User Agent
- <script>document.write(navigator.userAgent)
Das Ergebnis ist eine iPhone-Seite, die immer den aktuellen User-Agent des Browsers ausgibt:
36
Kapitel 1 – Mobile Designprinzipien
Bild 1.9: iPhone-Seite mit aktuellem User-Agent
Um eine Umleitung einzurichten, wäre es aber aufgrund der Vielzahl der möglichen UserAgent-Zeichenfolgen – der User-Agent ändert sich bei jeder neuen Spracheinstellung, beim Aktualisieren des Systems etc. – falsch, die komplette Zeichenfolge zu vergleichen. Stattdessen werden wir nur im User-Agent schauen, ob die Begriffe »iPhone«, »iPod« oder »Android« vorkommen. In JavaScript kann man das mit folgendem Code erreichen: if((navigator.userAgent.match(/iPhone/i)) || (navigator.userAgent.match(/iPod/i)) || (navigator.userAgent.match(/Android/i))) { if (document.cookie.indexOf("iphone redirect false") window.location "http://m.ihreseite.de"; }
1)
Dieser Code schaut also nach den oben genannten Begriffen und leitet, wenn sie im User-Agent vorkommen, automatisch auf die Seite m.ihreseite.de weiter. Beachten Sie, dass Sie bei der Zieladresse unbedingt das http:// voranstellen. Folgerichtig muss dieser Code auf der Desktop-Seite eingebaut werden: Browser Erkennung <script> if((navigator.userAgent.match(/iPhone/i)) || (navigator.userAgent. match(/iPod/i)) || (navigator.userAgent.match(/Android/i))) { if (document.cookie.indexOf("iphone redirect false") 1) window.location "http://m.ihreseite.de"; } Ich bin eine PC Seite!
1.3 Erkennung von mobilen Browsern und Desktop-Browsern
37
Bild 1.10: Wird der oben stehende Code von einem Desktop-Browser aufgerufen, bleibt der Benutzer auf der aufgerufenen Seite. Es wird nicht auf die mobile Seite umgeschaltet.
Bild 1.11: Ruft der Anwender den oben stehenden Code auf einem iPhone, einem iPod oder einem Android-Gerät auf, wird er auf die im Code angegebene Adresse weitergeleitet.
1.3.2
User-Agent mittels der .htaccess-Datei abfragen
Anstatt mit JavaScript zu arbeiten, können Sie auch in der .htaccess-Datei eines Verzeichnisses auf Ihrem Webserver eine ähnliche Weiterleitung realisieren. Eine .htaccess-Datei ist eine einfache Textdatei, die Sie mit jedem Texteditor, mit dem Sie auch HTML-Code schreiben, erstellen und bearbeiten können. Falls Sie sich bereits mit Webentwicklung auskennen, haben Sie bestimmt schon von dieser Datei gehört, die in der Regel immer dazu benutzt wird, bestimmte Verzeichnisse auf einem Webserver mit einem Passwort zu schützen. Die Angaben in dieser Datei können aber noch viel mehr – siehe hierzu auch das Kapitel 2.4 »Audio und Video«. Eine solche Datei zu erstellen, ist nicht immer einfach, da der volle Dateiname .htaccess lautet. Streng genommen handelt es sich um eine Datei, die keinen Namen besitzt, sondern nur die Endung .htaccess. Eine ganze Reihe von Texteditoren kann diesen Namen nicht abspeichern, da er mit dem Symbol einer Dateiendung beginnt. In diesem Fall müssen Sie einfach einen Buchstaben vergeben, die Datei abspeichern und sie dann auf dem Webserver umbenennen.
1.3.3
Geltungsbereiche der .htaccess-Datei auf dem Webserver
Da wir die .htaccess-Datei für eine Weiterleitung verwenden möchten, ist es absolut notwendig, uns kurz mit dem Geltungsbereich einer solcher Datei zu beschäftigen. Die .htaccess-Datei kann das Verhalten des Browsers in vielen Bereichen bestimmen. Dabei ist eine .htaccess-Datei für das Verzeichnis gültig, in dem sie sich befindet, aber auch für alle darin befindlichen Unterverzeichnisse, solange sich in denen keine neue .htaccessDatei befindet.
38
Kapitel 1 – Mobile Designprinzipien
Richten Sie also eine .htaccess-Datei für Ihr Verzeichnis www.ihreseite.de/web/ ein, dann sind die in der Datei enthaltenen Regeln auch gültig für www.ihreseite.de/web/beispiel oder www.ihreseite.de/web/adresse. Tragisch wird es, wenn Sie die Weiterleitungsregel in der .htaccess-Datei für das Verzeichnis www.ihreseite.de/web/ schreiben und mobile Benutzer zu Ihrer mobilen Adresse www.ihreseite.de/web/mobil schicken. In diesem Fall kommt ein mobiler Benutzer auf Ihre Seite, wird zu der mobilen Adresse geschickt, für die wiederum die Weiterleitungsregel gilt, und befindet sich ab sofort in einer Schleife, die auf dem iPhone mit dem Fehler Too many redirects (zu viele Weiterleitungen) endet. Unser Tipp daher: Verwenden Sie eine andere Webadresse oder eine neue .htaccessDatei im Zielverzeichnis ohne den Weiterleitungscode. Am einfachsten ist es, wenn Sie die .htaccess-Datei mit einem FTP-Programm auf dem Webserver anlegen. Wir zeigen Ihnen das am Beispiel von Cyberduck: 1. Gehen Sie in das Verzeichnis, in dem Sie Ihre Desktop-Webseite bereits haben oder anlegen wollen. Über die rechte Maustaste können Sie aus dem Kontextmenü die Option Neue Datei bzw. New File auswählen. 2. Vor dem Erstellen der Datei fragt Cyberduck Sie nach dem Dateinamen. An dieser Stelle geben Sie einfach .htaccess ein und klicken auf Create.
3. Anschließend wird die Datei als leeres File (0 Byte) auf dem Webserver erstellt. Mit der rechten Maustaste können Sie nun aus dem Kontextmenü die Funktion Bearbeiten mit bzw. Edit with und den entsprechenden Texteditor wählen. Falls Sie TextMate verwenden, wird dieser automatisch dort in das Menü eingebunden, und jegliche Änderungen werden von TextMate über die SichernFunktion auch direkt zurück auf den Webserver gespeichert.
1.3 Erkennung von mobilen Browsern und Desktop-Browsern
39
Ist die Datei erstellt, versehen Sie die .htaccess-Datei mit dem folgenden Code: RewriteEngine on RewriteCond %{HTTP RewriteRule ^(.*)$ RewriteCond %{HTTP RewriteRule ^(.*)$ RewriteCond %{HTTP RewriteRule ^(.*)$
USER AGENT} ^.*iPhone.*$ http://m.ihreseite.de [R 301] USER AGENT} ^.*iPod.*$ http://m.ihreseite.de [R 301] USER AGENT} ^.*Android.*$ http://m.ihreseite.de [R 301]
Beide vorgestellten Methoden funktionieren sehr gut, und es ist fast ein wenig Geschmackssache, auf welche Lösung Sie vertrauen wollen. Die .htaccess-Methode hat den Vorteil, dass der Benutzer etwas Zeit spart, da die Weiterleitungsregeln bereits beim Auslesen des Verzeichnisses verwendet werden und nicht erst, nachdem die erste Webseite geladen und das darin enthaltene JavaScript ausgeführt ist. Bei vielen Billig-Webservern wird Ihnen die Wahl automatisch abgenommen, da sie keine Veränderung oder Erstellung einer .htaccess-Datei zulassen. Informieren Sie sich daher bei Ihrem Hosting-Anbieter, ob Sie Zugriff auf die .htaccess-Dateien innerhalb Ihres Webspace haben. Exkurs: Die PHP-Variante Obwohl wir in diesem Buch PHP nicht weiter vorstellen oder verwenden, möchten wir Sie auch noch auf diese Variante aufmerksam machen. Sie hat ebenfalls den Vorteil, dass nicht erst der Inhalt einer Seite geladen werden muss und die Entscheidung, ob die mobile Seite oder die normale Seite aufgerufen wird, bereits auf dem Webserver fällt. Nur für PHP-Kenner – hier ist der passende PHP-Code: if(strstr($ SERVER['HTTP USER AGENT'],'iPhone') || strstr($ SERVER['HTTP USER AGENT'],'iPod') || strstr($ SERVER['HTTP USER AGENT'],'Android')) { header('Location: http://m.ihreseite.de'); exit(); }
40
Kapitel 1 – Mobile Designprinzipien
Lesezeichen http://bit.ly/bgvJGS Sollten Sie sich für PHP interessieren, bietet Franzis mit »Das Franzis-Lernpaket PHP/MySQL« einen soliden und leicht verständlichen Einstieg an.
1.3.4
Einen falschen User-Agent vorgeben
Wenn Sie viel auf Ihrem Desktop-Computer arbeiten und dort auch Ihre Webanwendungen testen möchten, ist es ratsam, dass sich Ihr Desktop-Browser nicht als PC, sondern als Mobiltelefon ausgibt. Insbesondere wenn Sie beispielsweise eine Android-Erkennung einbauen oder unterschiedliche Webseiten für iPhone-, Androidund BlackBerry-Plattformen erstellen, ist es oft einfacher, auf dem PC statt auf vielen verschiedenen Mobilgeräten zu testen. Einige gängige User-Agent-Strings haben wir bereits abgedruckt – den passenden String zu nahezu jedem Telefon auf der Welt können Sie im Internet finden. Am einfachsten lassen sich die User-Agents mit Safari umstellen. Ist das EntwicklerMenü aktiviert, können Sie aus einer ganzen Reihe verschiedener User-Agent-Strings wählen – angefangen bei Safari für Mac und Windows über Safari für iPhone, iPad und iPod touch bis hin zu Firefox und Opera. Alternativ können Sie über Anderer bzw. Other einen eigenen User-Agent-String eingeben, mit dem sich der Browser nun ausgeben soll.
Bild 1.12: Verschiedene User-Agents können bei Safari einfach aus dem Entwickler-Menü ausgewählt werden.
Firefox hat keine eingebaute Funktion zum Wechseln des User-Agents, man kann diese über die kostenlose Erweiterung User Agent Switcher aber nachrüsten. Die Erweiterung finden Sie auf der Webseite unter https://addons.mozilla.org/en-US/firefox/addon/59 und können sie von dort direkt in Firefox installieren. Nach dem erforderlichen Neustart des Browsers finden Sie im Tools-Menü den nun aktuell benutzten User-Agent angezeigt. User Agent Switcher bietet als einzigen mobilen User-Agent den iPhone-String an, lässt sich aber leicht um alle möglichen Strings erweitern. Dazu wählen Sie einfach Edit User Agents aus dem Tools-Menüeintrag aus und legen einen neuen User-Agent über New an. Glücklicherweise haben viele andere das schon gemacht und XML-Dateien mit vorgefertigten User-Agents im Internet veröffentlicht. Eine solche Liste finden Sie beispielsweise unter http://techpatterns.com/downloads/firefox/useragentswitcher.xml. Diese XML-
1.4 CSS- und JavaScript-Frameworks
41
Datei können Sie per Importfunktion über Edit User Agents laden und somit Ihr virtuelles Geräteportfolio um einige Dutzend neuer User-Agent-Strings erweitern. Für den Google Chrome-Browser gibt es bislang noch keine einfache Möglichkeit, den User-Agent zu modifizieren. Da Chrome aber, wie Firefox und Safari, auch mit Plug-ins, sogenannten Extensions, erweitert werden kann, lohnt es sich, bei Bedarf von Zeit zu Zeit unter https://chrome.google.com/extensions nach einer solchen Erweiterung zu suchen.
1.4
CSS- und JavaScript-Frameworks
Diese sogenannten Frameworks nehmen Ihnen in der Regel viel Arbeit ab. Sie brauchen nicht wie im vorangegangenen Beispiel jede Zeile CSS neu zu erfinden, sondern verwenden einfach die CSS-Dateien und Bilddateien, die mit dem Framework geliefert werden. Sie brauchen dann nur noch darauf zu achten, dass Sie im HTML-Code auf die richtigen Klassen verweisen. Das Aussehen einer Titelzeile, eines iPhone-Buttons oder der iPhoneSchieberegler wird komplett vom Framework bestimmt. Zwar brauchen Sie nur noch einen Bruchteil an Zeit (und Können), um eine mobile iPhone-Seite so zu gestalten, dass sie professionell aussieht, allerdings gibt es auch zwei Nachteile: •
Ein Framework enthält in der Regel immer mehr Definitionen und Code, als Sie für Ihr Projekt und Ihre Seite brauchen. Beispielsweise sind in den Frameworks oft verschiedene Farben für die Titelzeile einer iPhone-Webanwendung definiert, die Sie – außer Sie ändern per Hand den vordefinierten CSS-Code – alle installieren, obwohl Sie sehr wahrscheinlich nur eine Farbdefinition nutzen werden. Die Verwendung eines Frameworks bringt es zwangsläufig mit sich, dass ein Besucher Ihrer Seite mehr Daten auf sein mobiles Gerät laden muss als unbedingt notwendig. Falls Sie sich entscheiden, aus HTML-Code, CSS und JavaScript eine native Anwendung zu bauen, müssen die CSS-Framework-Daten nicht aus dem Netz heruntergeladen, aber mit der Datei gespeichert werden, was eine größere Datei nach sich zieht.
•
Die Namen der Selektoren und CSS-Klassen sind vorbestimmt, und Sie müssen Ihr HTML an diese Klassen anpassen bzw. von Anfang an Ihren HTML-Code so konzipieren. Den gleichen HTML-Code für eine normale Webseite und für eine mobile Seite zu benutzen, wird dadurch wesentlich schwieriger.
Zwei der Frameworks, iWebKit 5 und jQTouch, stellen wir Ihnen jetzt vor. Bei den Beispielen im Buch haben wir uns auf iWebKit 5 beschränkt, da dieses Framework einfacher zu verstehen ist und einen schnelleren Einstieg ermöglicht. Im Gegensatz zu iWebKit ist jQTouch dynamischer und bietet Ihnen mehr Effekte und Animationen, als Sie bei iWebKit finden werden.
1.4.1
iWebKit 5
iWebKit 5 ist ein sehr beliebtes und kompaktes CSS-Framework und kann unter http://iwebkit.net kostenlos heruntergeladen werden. Falls Sie Gefallen an dem Framework finden, sollten Sie einen Betrag per PayPal spenden.
42
Kapitel 1 – Mobile Designprinzipien
Das nächste Beispiel zeigt Ihnen einen ähnlichen HTML-Code wie den in unserem letzten Beispiel, in dem wir alle iPhone-CSS-Definitionen noch selbst gebaut hatten, allerdings werden div-Bereiche definiert. Anhand dieser div-Zuweisungen gestalten Sie die mobile Seite, da jeder div-Name für ein bestimmtes Element aus dem Framework steht. Um mit dem Framework zu arbeiten, müssen Sie es herunterladen, die ZIP-Datei entpacken und die Dateien und Ordner aus dem Verzeichnis Framework in das Verzeichnis Ihrer Webseite kopieren. Die CSS-Definitionen des iWebKit-Frameworks sind in den beiden Dateien style.css und developer-style.css definiert. Beide Dateien haben den gleichen Inhalt, allerdings wurden in der Datei style.css alle Leerzeichen und Zeilenumbrüche entfernt und somit einige KByte an Daten eingespart. Durch die fehlende Formatierung kann diese Datei aber nur von einem Browser verlässlich gelesen werden. Falls Sie wissen möchten, welche CSS-Selektoren definiert wurden, sollten Sie die Datei developer-style.css verwenden. Da wir bei der aktuellen Seite nur von einem mobilen Design ausgehen, wird auch nur auf die eine CSS-Datei mit link rel "stylesheet" type "text/css" href "style.css" verwiesen. Zwar enthält iWebKit die meisten iPhone-typischen Elemente, allerdings keine vordefinierte CSS-Klasse, mit der man die Abrundungen an Bildecken hervorrufen kann. Diese Funktion wird im HTML-Code mithilfe des style-Elements und der darin befindlichen CSS-Definition bestimmt: Jedes img-Tag im div-Bereich textimg erhält runde Ecken mit einem Radius von fünf Bildpunkten und einen dunkelgrauen Rand. Schon bei der Gestaltung der Titelzeile bemerken Sie den Komfort eines CSS-Frameworks. Sie müssen im Code einfach div id "topbar" und innerhalb dieser div-Definition den gewünschten Titel mit div id "title" einfügen, und schon haben Sie die Standardtitelzeile eines iPhones. In diesem Beispielcode haben wir die Kopfzeile noch weiter angepasst: Die Zeile div id "topbar" class "transparent" bewirkt eine leicht dunkle, transparente Titelzeile. Alternativ können Sie mit div id "topbar" class "black" auch eine komplett schwarze Titelzeile erstellen. Da beim iPhone diese Titelzeile auch zur Navigation verwendet wird, lassen sich mit iWebKit ganz einfach Navigationselemente in den Titel einbauen. Das Beispiel besitzt dazu einen blauen Button, den man oft in iPhone-Anwendungen als Anmeldebutton findet. Für unsere Beispielseite wollen wir dieses Navigationselement verwenden, um auf unsere Kontaktseite zu verweisen. Der blaue Button wird ebenfalls innerhalb des div id "topbar"-Bereichs mit folgender Zeile eingesetzt: Kontakt.
Insbesondere auf Unterseiten einer iPhone-Anwendung befinden sich auf der linken Seite der Titelzeile ein oder mehrere Pfeile, die es dem Benutzer erlauben, auf den vorangegangenen Bildschirm zurückzugehen. Diese Navigationspfeile lassen sich innerhalb der Titelzeilendefinition mit Zurück
für den Pfeil nach links und mit Weiter
für den Pfeil nach rechts definieren.
1.4 CSS- und JavaScript-Frameworks
43
Falls Sie anstatt eines Texts lieber ein Home-Symbol für den rechten Pfeil verwenden möchten, müssen Sie folgende HTML-Zeile einbauen:
Probieren Sie einfach die verschiedenen Variationen aus. Sie werden erstaunt sein, wie einfach sich eine professionell aussehende iPhone-Titelzeile erstellen lässt. Das nächste Element hatten wir im vorherigen Beispiel nicht verwendet, wir hätten dazu wahrscheinlich seitenweise CSS-Code abdrucken und erfinden müssen. Was Sie ebenfalls in vielen iPhone-Anwendungen finden, ist ein Suchfeld, das sich direkt unterhalb der Titelzeile befindet und in der Regel in grauer Schrift mitteilt, was man in diesem Feld suchen kann. Mittels iWebKit ist die Einbindung eines solchen Suchfelds ein Kinderspiel und erfordert in der Tat nur wenige Zeilen HTML-Code:
Mit div class "searchbox" legen Sie fest, dass die folgenden Zeilen HTML für den Inhalt und die Funktionsweise der Suchbox reserviert werden. Das form-Tag ist herkömmliches HTML und beschreibt eine Formulareingabe und was mit den Formulardaten geschehen soll. Interessant sind hier das Tag fieldset, das dem Browser mitteilt, dass alle folgenden Formularelemente in einer Gruppe zusammengefasst sind, und natürlich die beiden input-Tags für das Texteingabefeld sowie das unsichtbare submitTag, das ein Absenden des Formulars ermöglicht. Der eigentliche Inhalt einer iWebKit-Anwendung wird durch das Tag div id "content" definiert. Das erste Element ist eine graue Überschrift, die nicht über ein div, sondern einfach über eine Klasse des span-Tags definiert wird: <span class "graytitle">Spitzen Oldtimer von VW & Porsche
Im Gegensatz zum letzten Beispiel mit dem hausgemachten CSS haben wir die Überschrift etwas gekürzt, da die grauen Überschriften in der Regel nur einzeilig auftreten. Eines der wichtigsten Gestaltungselemente beim Arbeiten mit iWebKit ist die Definition der Seitenelemente (Page Items). Zusammengehörende Seitenelemente werden durch ul class "pageitem" definiert. Im nächsten Beispiel ist das erkennbar an den pageitem-Definitionen für die Textbox Wir führen und reparieren ... und die nachfolgende Menüstruktur. Beide Seitenelemente können weitere Unterelemente beinhalten (das Menü hat beispielsweise mehrere Menüpunkte), aber alle zu einem Seitenelement gehörenden
44
Kapitel 1 – Mobile Designprinzipien
Inhalte und Definitionen werden innerhalb von ul class "pageitem" zusammengefasst. Text stellt man am besten, wie im Beispiel gezeigt, durch die Definition einer Textbox dar:
Damit ist kein Texteingabefeld gemeint, sondern ein sich vom grauen Untergrund abhebender Bereich für die Textanzeige. Besonders einfach ist auch der Einbau von Touchfeldern für Links. Innerhalb einer Seitenelementdefinition können folgende Bereiche definiert werden: •
die Zielseite mittels des Tags a href "",
•
ein Icon,
•
die Bezeichnung des Links sowie
•
ein Pfeil nach rechts, der kenntlich macht, dass es sich bei dem Feld um einen Verweis auf eine neue Seite handelt.
Im HTML-Code sieht das wie folgt aus:
<span class "name">Preisrechner <span class "arrow"> Die Klasse menu ruft das Design eines Touch-Menüfelds auf, das Tag a href "" verweist auf die Zielseite preisrechner.html. Piktogramme und Icons können ohne Klassenzuweisung im img-Tag eingefügt werden, während für die Linkbezeichnung die Klasse span class "name" und für den Pfeil die Klasse span class "arrow"> angegeben werden muss. Zum Abschluss zeigt unser Beispiel noch einmal die Verwendung eines Seitenelements, das neben einer Textbox auch ein Bild enthält. Im Kopfbereich der HTML-Datei hatten wir definiert, dass dieses Bild, da es innerhalb des textimg-divBereichs liegt, die für das iPhone typischen Abrundungen erhält. Optisch abgesetzt ist der Fußbereich, der einfach über div id "footer" definiert wird und sich insbesondere in der Schriftgröße vom Rest des Inhalts absetzt.
1.4 CSS- und JavaScript-Frameworks
45
Jetzt folgt der Beispielcode einer iPhone-Seite mit iWebKit-CSS-Selektoren: ! Einfaches HTML Beispiel mit iWebKit CSS Selektoren Markus Spiering > Oldtimer Spiering <meta name "viewport" content "width device width; initial scale 1.0; maximum scale 1.0; user scalable 0;" /> <style> Oldtimer Spiering Kontakt <span class "graytitle">Spitzen Oldtimer von VW & Porsche
- <span class "name">Aktuelle Angebote<span class "arrow">
- <span class "name">Unsere VWs<span class "arrow">
46
Kapitel 1 – Mobile Designprinzipien
- <span class "name">Unsere Porsche<span class "arrow">
- <span class "name">Reparaturen<span class "arrow">
- <span class "name">Preisrechner <span class "arrow">
<span class "graytitle">Wir importieren aus Kalifornien!
Oldtimer Spiering
Beispielgasse 1, 12345 Bad Beispielstadt
1.4.2
Verwendete Ressourcen speichern
Speichern Sie alle bislang verwendeten Ressourcen und Dateien in einem Verzeichnis namens iWebKit_Beispiel. Wir werden auf dieses Beispiel am Ende des Buchs zurückkommen, wenn wir aus dieser einfachen mobilen Webseite eine native iPhone-Anwendung bauen. Der Inhalt des Verzeichnisses sollte bislang wie folgt aussehen:
Bild 1.13: Verwendete Ressourcen speichern.
1.4 CSS- und JavaScript-Frameworks
47
Es gibt eine Reihe weiterer div-Identifikatoren, die das Aussehen einer Webanwendung beeinflussen, auch wenn sie bislang noch nicht genannt wurden. Einige davon werden Sie im weiteren Verlauf dieses Buchs kennenlernen, da wir iWebKit für die meisten Beispiele verwenden. Auf einige weitere Elemente des Frameworks möchten wir allerdings noch in dem nächsten Beispiel eingehen. Safari Web Inspector, Google Chrome Developer Tools und Firebug Ohne eines dieser Tools für den Desktop-Browser kommt kaum ein Webentwickler aus. Alle drei sind relativ ähnlich und werden schnell unabdingbar, wenn Sie sie einmal benutzt haben. Safari Web Inspector Als wir ganz am Anfang des Buchs über die verschiedenen Webbrowser sprachen, wurde schon erwähnt, dass das Entwickler-Menü in Safari nicht nur die Möglichkeit anbietet, den User-Agent eines iPhones zu simulieren, sondern auch noch weitere nützliche Funktionen enthält. Eine besonders hilfreiche Funktion ist der Web Inspector – im deutschen Safari zu finden unter Entwickler/Webinformationen einblenden. Um den Web Inspector nutzen zu können, müssen Sie das Entwickler-Menü in den Safari-Einstellungen aktiviert haben. Wie das genau funktioniert, können Sie in der Einführung oben im Abschnitt über Safari unter »Welcher Browser?« nachlesen.
Bild 1.14: Den Web Inspector kann man über Inspect Element aus dem Kontextmenü oder über Show Web Inspector aus dem Menü Develop aufrufen. In der deutschen SafariVersion wählen Sie Entwickler/Webinformationen einblenden.
Sobald Sie in Safari das Develop-Menü aktiviert haben, rufen Sie einfach eine unserer Beispielseiten auf, klicken mit der rechten Maustaste auf ein Element auf der Seite und wählen Inspect Element aus.
48
Kapitel 1 – Mobile Designprinzipien
Bild 1.15: HTML-Tags, Klassen und CSSDefinitionen auf einem Blick.
Daraufhin öffnet sich der Web Inspector und zeigt Ihnen nicht nur den HTML-Code mit all seinen definierten Klassen an, sondern bietet Ihnen auch eine Ansicht der benutzten CSS-Definitionen für das jeweilige Element an. Sie können sich mit den kleinen Pfeilen am linken Rand durch den ganzen Seitencode klicken und somit Element für Element der Seite analysieren. Insbesondere bei der Fehlersuche ist der Web Inspector unwahrscheinlich hilfreich. Am unteren Rand sehen Sie, in welcher Ebene sich das aktuell ausgewählte Element befindet. In unserem Beispiel befindet sich das Element
Wie viel kostet Sie ein Oldtimer
im HTML-Dokument innerhalb des body-Bereichs unter dem div-Container content, dem ul-Tag mit der Klasse pageitem und dem li-Tag mit der Klasse textbox.
Bild 1.16: Die ResourcesAnsicht erlaubt eine genaue Analyse der Ladezeiten für eine Seite.
1.4 CSS- und JavaScript-Frameworks
49
Insbesondere wenn Sie umfangreichere Webseiten verfassen, lohnt sich auch die ResourcesAnsicht innerhalb des Web Inspectors, um die Ladezeiten der einzelnen Elemente zu analysieren und festzustellen, ob wirklich alle Dateien geladen werden konnten. Google Chrome Den Safari Web Inspector finden Sie in Chrome ebenfalls, nur umbenannt in Developer Tools. Ansonsten sind die Funktionen und selbst das Aussehen des nützlichen Werkzeugs gleich. Firefox Firebug Firefox ist leider (noch) nicht von Haus aus ausgestattet mit einer derartigen Funktion, selbst wenn Firefox der erste Browser war, der mit einem derartigen Tool benutzt werden konnte. Das kommt daher, dass das Firefox-Plug-in Firebug zu den beliebtesten Webentwicklungs-Tools gehört. Um Firebug zu benutzen, müssen Sie das Plug-in von www.getfirebug.com in Firefox herunterladen und installieren. Die Funktionsweise ist nahezu identisch mit dem Safari Web Inspector.
1.4.3
Form-Elemente mit iWebKit 5
Im folgenden Abschnitt erfahren Sie, wie Sie Form-Elemente mit dem iWebKitFramework erstellen können. Dazu ein einfaches Beispiel: Oldtimer Spiering <meta name "viewport" content "width device width; initial scale 1.0; maximum scale 1.0; user scalable 0;" /> <meta name "apple mobile web app status bar style" content "black"/> Zurück Preisrechner
<span class "graytitle">Auto & Baujahr:
50
Kapitel 1 – Mobile Designprinzipien
- <select name "markemodell"> Volkswagen Käfer Volkswagen Bus Volkswagen Karmann Ghia <span class "arrow">
- <select name "baujahr"> 1955 1968 1969 1978 1979 1985 1986 und älter <span class "arrow">
<span class "graytitle">Zustand:
- <span class "name">Voll restauriert
- <span class "name">Zum Teil restauriert
- <span class "name">Schrott
<span class "graytitle">Persönliche Angaben:
- <span class "name">Name
- <span class "name">Telefon
Oldtimer Spiering
Beispielgasse 1, 12345 Bad Beispielstadt
1.4 CSS- und JavaScript-Frameworks
51
Bild 1.17: Beispielseite mit Titelzeilennavigation und geöffneter Auswahlliste.
Unser Beispiel zeigt eine Unterseite der Oldtimer-Seite und verwendet somit in der Titelleiste einen Linkspfeil, um wieder auf die Hauptseite zurücknavigieren zu können. Pfeil und Link werden einfach über die Zeile Zurück
definiert. Sie sehen in dem Beispiel, dass wir die Umlaute mit einem HTML-Code umschrieben haben. Umlaute, andere Sonderzeichen oder auch HTML-eigene Zeichen wie sollten immer mit einem HTML-Code umschrieben werden. Eine komplette Tabelle der HTML-Sonderzeichen und -Codes finden Sie hier: http://www. asciizeichen.de/HTML.html. Die ersten Auswahloptionen auf der Beispielseite sind sogenannte Auswahlboxen. Im PC-Browser werden sie meistens als Drop-down- bzw. Pop-up-Menü angezeigt, auf dem iPhone erscheinen sie als scrollbare Auswahlliste am unteren Bildschirmrand, und bei Android-Telefonen werden diese Auswahlboxen als Menü über die Webseite angezeigt. Ein Auswahlmenü besteht aus einem li class "select"-Eintrag mit mehreren definierten Optionen, beispielsweise: Volkswagen Bus
Der ausgewählte Wert wird nach dem Abschicken des Formulars im Feld value übertragen.
Bild 1.18: Das Formular mit Radiobuttons.
52
Kapitel 1 – Mobile Designprinzipien
Die vom PC-Browser gewohnten Radiobuttons werden bei iWebKit und in vielen iPhoneAnwendungen nicht als normale Radiobuttons angezeigt, sondern als einzeilige Einträge mit einer Markierung am rechten Bildschirmrand. Radiobuttons werden verwendet, wenn der Benutzer aus einer Reihe von Optionen nur eine Option auswählen kann. Eine Liste dieser Schaltflächen wird mit li class "radiobutton" für jeden Eintrag definiert. Im li-Tag wird über die span-Zuweisung mit der Klasse name der Titel definiert und mit dem input-Tag die eigentliche Funktionsweise des Radiobuttons bestimmt.
Bild 1.19: Formular mit Texteingabefeldern des Typs smallfield.
Am unteren Ende des Beispiels befinden sich zwei weitere Texteingabefelder. iWebKit bietet drei verschiedene Arten von Texteingabefeldern. Der im Beispiel gezeigte Typ (smallfield) erlaubt neben dem eigentlichen Texteingabefeld noch die Angabe einer Bezeichnung, beispielsweise Name: oder Telefon:. Die Definition des Placeholders (Ihr Name) ist optional, kann aber den Benutzer auf das gewünschte Eingabeformat hinweisen. Sobald der Benutzer das Texteingabefeld auswählt, verschwindet der placeholderText. Eine andere Variante eines Texteingabefelds ist bigfield. Diese Art wird nicht im Beispiel gezeigt, allerdings haben Sie sicherlich diese Art von Texteingabefeldern bereits auf einem iPhone oder einem anderen High-End-Telefon gesehen. Das Texteingabefeld erstreckt sich über nahezu die gesamte Bildschirmbreite und hat keine nebenstehende Bezeichnung. Als Kennzeichnung und als Hinweis darauf, was der Benutzer eingeben muss, wird auch hier die placeholder-Definition innerhalb des input-Tags verwendet. Beispiele von bigfield-Eingabefeldern finden Sie sehr oft auf Anmeldebildschirmen, auf denen Sie Ihren Benutzernamen und Ihr Passwort eingeben müssen. Um mehr als eine Zeile oder einige Worte Text abzufragen, müssen Sie ein normales Texteingabefeld verwenden. Dies wurde zwar nicht im letzten Beispielcode gezeigt, kann aber sehr einfach mit den folgenden Zeilen definiert werden:
1.4 CSS- und JavaScript-Frameworks
53
Die Angabe von rows bezeichnet die maximale Anzahl der dargestellten und erlaubten Zeilen. Als letztes Form-Element im Beispiel wird mit li class "button" noch eine Schaltfläche zum Absenden der Daten definiert. Sie werden vielleicht bemerkt haben, dass ein wichtiges Form-Element fehlt: die An-/ Aus-Schieberegler, die das iPhone aus dem checkbox-Element generiert. Natürlich unterstützen iWebKit und andere CSS-Frameworks auch dieses Element, allerdings werden diese Schieberegler nicht aus CSS-Rechtecken gezeichnet, sondern es werden einfach Bilder der Schaltflächen geladen. Diese Bilder reagieren nicht auf die Sprachauswahl der Seite und werden – egal ob Sie Ihre Webseite in Deutsch, Englisch oder einer anderen Sprache verfassen – immer als englisches Bild geladen und dargestellt. Wenn das kein Problem ist, binden Sie für eine sogenannte Checkbox folgenden Code in Ihr -Element und untergeordnete ul class "pageitem"-Elemente ein:
<span class "name">Neuwertig Falls Sie Schaltflächen in Deutsch benötigen, kommen Sie nicht darum herum, sie selbst mit einer Bildbearbeitungssoftware umzugestalten und die folgende Datei im iWebKitFramework auszutauschen: Framework/images/checkbox.png. Achten Sie darauf, nicht die Position oder die Größe der Schaltflächen zu ändern.
1.4.4
jQuery und jQTouch
Wir möchten Ihnen jetzt die wirklich fantastischen Möglichkeiten der JavaScriptFrameworks jQuery und jQTouch vorstellen. Mithilfe dieser Frameworks lassen sich ebenfalls iPhone-Seiten erstellen, die nicht nur das vom iPhone bekannte Aussehen haben, sondern auch von iPhone-Anwendungen bekannte Animationen mit nur wenigen Zeilen Code ermöglichen. Selbst wenn wir jetzt detailliert auf jQTouch eingehen, bevorzugen wir bei unseren Beispielen im Buch, möglichst konsistent die eben vorgestellte CSS-Bibliothek iWebKit 5 zu verwenden. Der Grund dafür ist einfach: Um Ihnen die Möglichkeiten mit HTML5 näher zu bringen, brauchen wir keine Effekte in der Benutzeroberfläche, allerdings wollen wir Ihnen eine gut aufgeräumte und klare UI in den Beispielen bieten. Daher fällt unsere Wahl im Buch auf iWebKit 5. Falls Ihnen die Möglichkeiten mit jQTouch attraktiver erscheinen, werden Sie sehen, dass sich alle Beispiele im Buch ganz einfach auf jQTouch umschreiben lassen. Das Framework jQuery ist mittlerweile die weltweit am meisten verwendete JavaScriptBibliothek. Sie erlaubt es den Programmierern, mit wenig Aufwand umfangreiche JavaScript-Funktionen beispielsweise zur Navigation in die eigenen Projekte zu integrieren. Während jQuery keine mobilspezifischen Funktionen zur Verfügung stellt, ist jQTouch komplett auf iPhone und iPod touch ausgerichtet. Das jQTouch-Framework ist ein Plug-in für jQuery und benötigt diese Bibliothek.
54
Kapitel 1 – Mobile Designprinzipien
Ein paar Worte zur Kompatibilität: jQTouch ist großartig, wenn Sie eine Webanwendung für das iPhone, das iPad oder den iPod touch erstellen möchten, aber wir sind oft in Probleme mit anderen Plattformen und WebKit-Browsern geraten. Während alle Beispiele im Buch mindestens auf dem iPhone oder unter Android laufen sollten, beschränken sich die jQTouch-Beispiele zu diesem Zeitpunkt auf iOS. Manche Animationen (Slide-ups) sind auf einigen Android-Telefonen so langsam, dass sie kaum benutzbar sind. Volle Unterstützung für Android dürfte aber in Kürze zu erwarten sein. Die Frameworks in den Code einbinden Um jQTouch zu benutzen, muss auch jQuery in den Code mit eingebunden werden. Sie können jQuery zum einen von http://jquery.com herunterladen und die Datei jquery1.4.2.min.js (bzw. eine neuere Version) auf Ihrem Server speichern oder über die folgenden Zeilen im HTML-Header dynamisch von den Google-Servern laden: <script type "text/javascript" src "http://www.google.com/jsapi"> <script type "text/javascript"> google.load("jquery", "1.4.2");
Die verschiedenen jQTouch-Dateien und -Verzeichnisse sollten Sie auf Ihrem Webserver speichern. Um die aktuelle jQTouch-ZIP-Datei herunterzuladen, gehen Sie einfach auf http://www.jqtouch.com und klicken dort auf Download.
Bild 1.20: Inhalt und Struktur des jQTouch-ZIP-Archivs.
Entpacken Sie die ZIP-Datei und kopieren Sie die Verzeichnisse jqtouch, themes und extensions auf Ihren Webserver. Fügen Sie dann im Header des HTML-Dokuments unterhalb der jQuery-Zeilen folgenden Code ein: <script type "text/javascript" src "jqtouch/jqtouch.js">
In der ersten Zeile wird die jQuery-JavaScript-Bibliothek eingebunden, in den beiden folgenden Zeilen folgen die von jQuery verwendeten CSS-Definitionen, die zur Oberflächengestaltung benutzt werden. Wie Sie vielleicht schon bemerkt haben, bietet
1.4 CSS- und JavaScript-Frameworks
55
jQTouch zwei verschiedene Themes, also zwei unterschiedliche Motive. Diese Themes bestimmen das Aussehen der gesamten Anwendung:
Bild 1.21: Das jqt-Theme gibt den Webanwendungen eine sehr stylische Oberfläche, die an native iPhone-Apps erinnert.
Bild 1.22: Das apple-Theme ist konservativer und bietet, wie auch in iWebKit 5, eine Oberfläche, die sehr an die Standard-Apps des iPhones erinnert. Das Einzige, was wir am Code für diese beiden Screenshots verändert haben, ist jeweils der Verweis auf das jqtund das apple-Theme.
Bevor wir zu dem eigentlichen Inhalt der Webanwendung kommen, muss jQTouch noch initialisiert werden. Über die folgende Initialisierung werden alle jQTouch-Funktionen im Code bereitgestellt und können verwendet werden. Falls Sie die folgenden Zeilen im head-Bereich vergessen, erhalten Sie, egal wie viel HTML-Code Sie schreiben, immer nur einen schwarzen Browserbildschirm. <script type "text/javascript"> var jQT $.jQTouch({ });
Seiten innerhalb der Webanwendung anlegen Im Gegensatz zu einem normalen Webauftritt werden alle Seiten einer jQTouch-Webanwendung innerhalb einer HTML-Datei angelegt. Anstatt also mehrere einzelne HTML-Seiten, wie beispielsweise •
index.html
•
angebote.html
•
kontakt.html
56
Kapitel 1 – Mobile Designprinzipien
zu generieren, erstellen wir mit jQTouch nur eine index.html mit verschiedenen divoder form-Tags jeweils mit einer eigenen ID im Code:
Mit diesem Beispiel haben wir zwei leere Seiten innerhalb unserer jQTouch-Webanwendung erstellt. Der div class "current"-Parameter ist optional und bezeichnet die Seite, die als Startseite für die Webanwendung genutzt werden soll. Wird diese Klassenzuweisung weggelassen, wird die erste ID nach dem body-Tag als Startseite benutzt. Innerhalb der einzelnen div-Container können Sie die Seiten mit eigenem HTML und CSS gestalten. jQTouch bietet Ihnen aber auch, ähnlich wie iWebKit 5, vorgefertigte Elemente, die meistens nicht nur besser aussehen, sondern teilweise auch mit einem bestimmten Verhalten versehen sind. Als erstes Element werden wir auch in diesem Beispiel die Kopfzeile, also die Toolbar, wieder in iPhone-gerechtes Styling bringen. Dazu geben wir folgenden Code in den ersten div-Container ein: Oldtimer Kontakt
Bild 1.23: Stylische Kopfzeile mit Titel und Button.
Der Titel einer Kopfzeile wird innerhalb eines h1-Tags beschrieben. Weiterhin haben Sie die Möglichkeit, zwei Schaltflächen innerhalb der Kopfzeile zu definieren. Sie werden einfach innerhalb des div class "toolbar"-Containers als Links definiert. Da sich alle Seiten einer jQTouch-Anwendung innerhalb einer Datei befinden, dürfen Sie keine externen Links, sondern nur Links zu den anderen div-Containern erstellen, die eine Seite der Webanwendung beinhalten. Auch wenn wir noch keine Inhalte für die beiden Seiten haben, lassen Sie uns dennoch das Beispiel mit einer Kopfzeile für den zweiten Container vervollständigen. Der Code der Beispielanwendung sollte jetzt so aussehen: <meta name "layout" content "webkit" />
1.4 CSS- und JavaScript-Frameworks
57
Oldtimer Spiering <script type "text/javascript" src "http://www.google.com/jsapi"> <script type "text/javascript"> google.load("jquery", "1.3.2"); <script type "text/javascript" src "jqtouch/jqtouch.js"> <script type "text/javascript"> var jQT $.jQTouch({ }); Oldtimer Kontakt Kontakt Zurück
Wenn Sie dieses Beispiel ausführen, sollten Sie folgendes Verhalten bereits sehen können: Die Webanwendung besitzt eine Kopfzeile mit einem Button, der im div-Container der Klasse toolbar durch einen einfachen a href ""-Verweis definiert wurde. Um den Button auch als Button erscheinen zu lassen, muss dem a-Tag die Klasse button zugewiesen werden. So etwas kannten Sie wahrscheinlich bisher nur von nativen iPhone-Anwendungen. Nach Antippen von Kontakt dreht sich der Bildschirm zur Kontaktseite. Die Animation wird durch die Angabe von flip innerhalb der Klassendefinition des a-Tags erreicht.
58
Kapitel 1 – Mobile Designprinzipien
Bild 1.24: Kopfzeile mit einem Button.
Bild 1.25: Nach dem Antippen von Kontakt dreht sich der Bildschirm zur Kontaktseite.
Der Inhalt des Containers div id "kontakt" wird jetzt als einzelne Seite dargestellt. Dabei wird für die Zurück-Funktion die gleiche Animation verwendet. Der Stil des Zurück-Buttons kommt durch die Spezifikation von back innerhalb der Klassendefinition des a-Tags. Im Gegensatz zu nativen iPhone-Anwendungen müssen Sie in jQTouch (wie auch in iWebKit 5) den Zurück-Button mit dem Namen Zurück versehen.
Bild 1.26: Der Inhalt des Containers wird als einzelne Seite dargestellt.
1.4 CSS- und JavaScript-Frameworks
59
Listen und Animationen Nachdem wir bereits eine Anwendung mit einer Kopfzeile haben, wollen wir ein weiteres iPhone-typisches Element hinzufügen: Linklisten. Im iWebKit 5-Beispiel haben wir auf der Startseite eine Reihe von Links angeboten, und das lässt sich mit jQTouch ähnlich bewerkstelligen. Fügen Sie einfach unterhalb der Kopfzeilendefinition im homeContainer den folgenden Code hinzu:
- Kontakt
Damit diese Links auch funktionieren, müssen im Code div-Container für weitere Unterseiten mit den IDs angebote, repair und preisrechner angelegt werden. Listen werden wie in iWebKit 5 über die Tags ul und li angelegt. Dabei kann das liTag folgende Klassen haben: •
arrow – der für iPhone-Links typische Linkpfeil wird verwendet.
•
forward – ein buttonähnlicher Pfeil wird statt des normalen Linkpfeils verwendet.
Bild 1.27: Die Startseite unseres Beispiels sieht nun so aus.
Beim Antippen der Links wird ebenfalls eine leichte Animation verwendet: Der aktuelle Bildschirm rollt zur linken Seite, und die Zielseite wird von der rechten Seite hereingescrollt. Sie können das durch die Angabe der folgenden Klassen im a-Tag beeinflussen: Klasse
Beschreibung
Die neue Seite wird vom unteren Rand in den Bildschirm gerollt.
Die alte Seite wird langsamer ausgeblendet.
Die Seiten werden langsamer aus- und eingeblendet.
60
Kapitel 1 – Mobile Designprinzipien
Klasse
Beschreibung
Diese Animation haben wir schon kennengelernt. Der Bildschirm dreht sich um eine vertikale Achse, um die neue Seite anzuzeigen.
Die neue Seite wird aus der Mitte des Bildschirms hereingezoomt.
Eine recht aufwendige Animation. Die alte Seite wird verkleinert und verschwindet gleichzeitig im Hintergrund, während die neue Seite aus dem Hintergrund hereingezoomt wird.
Hier sind die beiden Seiten wie auf Würfelseiten projiziert, und der Würfel dreht sich einmal um die eigene Achse, um die Seiten auszutauschen.
Die einzelnen Animationen lassen sich schwer mit Worten beschreiben. Ausprobieren geht hier definitiv über Studieren. Um wieder auf die vorhergehende Seite zurückzukehren, können wir die Klasse back in der Linkdefinition verwenden, allerdings können auch die Klassen cancel und goback verwendet werden. Sollten Sie keinerlei Animationen in Ihrer Webanwendung verwenden wollen, können Sie das im Header-Bereich des Codes, in dem jQTouch initialisiert wird, global festlegen. Ändern Sie einfach die Initialisierungszeile wie folgt: var jQT
$.jQTouch({useAnimations: false});
Ab sofort können Sie noch so viele Animationen in Ihren Linkklassen definieren – die Seiten werden ohne Schnickschnack einfach geladen und angezeigt. Wie auch iWebKit 5 kann jQTouch verschiedene Arten von Listen darstellen: Welche Art von Liste angezeigt werden soll, wird durch eine Klassenzuweisung im ul-Tag definiert. Fügen Sie beispielsweise einfach die Klasse rounded dem ul-Tag im Beispielcode hinzu:
Wie der Name der Klasse schon erahnen lässt, sind die Kanten der Linkumrandungen nicht mehr eckig, sondern abgerundet: Das Ganze geht natürlich auch wesentlich radikaler. Falls Sie es noch nicht getan haben, erstellen Sie jetzt für das Beispiel einen div-Container mit der ID angebote. Der folgende Code erstellt wiederum eine Listenansicht: Angebote Zurü ck - Unter 1000 Euro
- Lenkrad
1.4 CSS- und JavaScript-Frameworks
61
- Bremse
- Unter 2000 Euro
- Motorhaube
- Achse
Die Klasse edgetoedge definiert Linkfelder von der rechten Bildschirmseite bis zur linken Seite – es gibt also keine unklickbare Fläche links und rechts wie bei rounded. Mit der Klasse sep können Überschriften und Separatoren im li-Tag definiert werden:
Bild 1.28: Mit edgetoedge definierte Linkfelder.
Ein weiterer Stil ist plastic, der im Gegensatz zu edgetoedge die Klassen arrow und forward für das li-Tag unterstützt: - Unter 1000 Euro
- Lenkrad
- Bremse
- Unter 2000 Euro
- Motorhaube
- Achse
Bei plastic erstrecken sich die Linkfelder ebenfalls von Bildschirmrand zu Bildschirmrand, und die Hintergrundfarbe alterniert pro Link.
62
Kapitel 1 – Mobile Designprinzipien
Bild 1.29: Mit plastic definierte Linkfelder.
Als letzten Listenstil möchten wir Ihnen das auffällige metal vorstellen. - Unter 1000 Euro
- <small>NEUBremse<em>Ohne
"">Motorhaube "">Achse
Der Stil unterstützt nicht die forward-Klassifizierung für das li-Tag, beherrscht aber zusätzliche Beschreibungen, die mit small und em, wie im Beispiel gezeigt, in das Linkfeld mit eingearbeitet werden können: Auch in den anderen Listenformen kann das Tag small definiert werden. Hier ein Beispiel mit der Standardlistenansicht: - Preisrechner<small> NEU
- Ungelesene E Mails <small class counter>112
Lassen Sie uns jetzt noch die Startseite der Anwendung etwas aufhübschen. Fügen Sie unter dem toolbarContainer die folgende Zeile hinzu: Bitte wählen Sie:
1.4 CSS- und JavaScript-Frameworks
63
Des Weiteren setzen Sie unterhalb der auf der Startseite definierten Liste noch folgenden div-Container ein: Oldtimer Spiering
Beispielgasse 1, 12345 Bad Beispielstadt
Und schon sieht unsere Startseite wie eine richtige iPhoneAnwendung aus: Letztendlich ist der Gestaltungsprozess ähnlich wie der unter iWebKit 5: Sie schreiben größtenteils HTML-Code und weisen den HTML-Elementen vordefinierte CSS-Klassen zu, die nicht nur das Aussehen verändern, sondern teilweise auch Animationen hinzufügen.
1.4.5
Formulare mit jQTouch
Als Nächstes werden wir uns die Formulardefinitionen mit jQTouch ansehen. In unserem Beispiel werden wir die KontaktSeite als Formular umschreiben. Dazu entfernen Sie einfach den div-Container mit der ID kontakt und kopieren folgenden Code in das Beispiel: Kontakt Zurück - Newsletter<span class "toggle">
Absenden Abbrechen
Zuerst wird ein Formular mit dem form-Tag initiiert und erst einmal kein Zielort angegeben, an den die Daten geschickt werden sollen. Wichtig im form-Tag ist die Angabe der ID, da der div-Container mit der id kontakt gelöscht wurde. An seine Stelle tritt nun der form-Bereich. Sie erkennen also, dass eine einzelne jQTouch-Seite nicht nur aus einem div-Container bestehen kann, sondern auch aus einem Formular.
64
Kapitel 1 – Mobile Designprinzipien
Anschließend haben wir wieder eine Kopfleiste mit einer Zurück-Option eingefügt und beginnen dann mit den eigentlichen Formularfeldern. Das erste Eingabefeld würde einen Wert in der Variablen nachname abspeichern. Vor der Texteingabe wird direkt auf dem Textfeld Ihr Name angezeigt, wodurch der Benutzer sehen kann, was er dort eingeben soll. Das Gleiche machen wir für das Feld mit der Telefonnummer. Da wir den An- und Ausschalter optisch von der Eingabe des Namens und der Telefonnummer getrennt haben möchten, wurde für dieses Element ein eigenes ul-Tag aufgemacht und mit der Klasse rounded versehen. Der Schieberegler wird durch span class "toggle" und dem nachfolgenden input-Tag definiert.
Bild 1.30: Das erste Formular mit jQTouch.
Die beiden Buttons im Formular werden ganz einfach über die beiden letzten a-Tags im Formular definiert. Dabei soll der Button zum Absenden des Formulars in weißer Farbe erscheinen, was durch die Klasse whiteButton erreicht wird. Dass dies auch der Submit-Button ist, wird durch die Klasse submit definiert. Alternativ dazu der Abbrechen-Button: Dieser soll in dunkelgrauer Farbe angezeigt werden (Klasse grayButton) und soll, ohne die Daten abzusenden, einfach wieder zurück auf die letzte Seite springen. Auch das kann einfach über die Angabe der Klasse goback erreicht werden. Texteingabefelder für Passwörter werden ebenfalls mit dem input-Tag erstellt, allerdings wird hier der Typ mit type password auf ein Passwortfeld gesetzt: Passworteingabe:
Auswahllisten, die auf dem iPhone mit dem bekannten Rollauswahlfenster dargestellt werden, sind über den folgenden Code möglich: Marke wählen: - <select id "auto">
1.4 CSS- und JavaScript-Frameworks
65
Käfer Karmann Ghia Hippie Bus 911 365
Beachten Sie, wie man über das Tag optgroup unanklickbare Kategorienfelder innerhalb der Auswahlliste definieren kann.
Bild 1.31: Passwortfeld und Auswahlliste in einem jQTouch-Formular.
Was jetzt noch fehlt, sind Checkboxen und Radiobuttons im Formular. Diese sind mit den jeweiligen HTML-Zeilen schnell im Formular eingefügt: Checkboxen zur Multi Auswahl: Entweder oder:
Jeweils die erste Option wurde über checked "checked" vorausgewählt.
66
Kapitel 1 – Mobile Designprinzipien
Bild 1.32: Checkboxen und Radiobuttons funktionieren auch im Querformat.
1.4.6
jQTouch-Fehler für Radiobuttons
Auch die besten Frameworks und Bibliotheken sind nicht frei von Fehlern. So auch jQTouch nicht, zumindest zu dem Zeitpunkt, da wir dieses Buch im Sommer 2010 geschrieben haben. Wenn Sie den oben stehenden Code für die Radiobuttons verwendet haben, haben Sie alles richtig gemacht, und trotzdem werden die Radiobuttons nicht wie gewünscht auf einem Gerät funktionieren. Sie arbeiten im Desktop-Webbrowser, aber nicht auf dem iPhone oder einem iPod touch. Glücklicherweise können Sie den jQTouch-Fehler im Handumdrehen selbst beheben. Rufen Sie die jQTouch-JavaScript-Datei jqtouch.js aus dem Verzeichnis jqtouch in Ihrem Texteditor auf. Dort wird in Zeile 159 die JavaScript-Funktion body.click definiert: $body.click(function(e){ var $el $(e.target); if ($el.attr('target') ' blank' || $el.attr('rel') $el.is('input[type "checkbox"]')) { return true; } else { return false; } });
'external' ||
Tauschen Sie die Zeile mit der if-Bedingung durch die folgenden Zeilen aus: if ($el.attr('target') ' blank' || $el.attr('rel') 'external' || $el.is('input[type "checkbox"]') || $el.is('input[type "radio"]'))
Speichern Sie anschließend die Datei wieder auf dem Server ab, und das Problem ist behoben.
1.4.7
Dynamische Inhalte
Nun würden wir eine ziemlich langweilige Anwendung programmieren, die nur auf statische Daten innerhalb der einen HTML-Datei zugreifen könnte. jQTouch kann durch
1.5 HTML und Telefonfunktionen
67
die Verwendung der AJAX-Technologie externe Dateien und Daten aus dem Internet holen, ohne die aktuelle Seite neu laden oder eine andere Seite laden zu müssen. Um das zu verdeutlichen, kopieren Sie einfach den Code, den wir für das Kontaktformular verwendet haben, in eine neue Datei und speichern ihn unter dem Dateinamen form.html auf dem Server ab: Kontakt Zurück ...
Für diese HTML-Datei brauchen Sie keinen - oder -Bereich zu definieren, sondern Sie verwenden wirklich ganz genau den Code der Haupt-HTML-Seite unseres Beispiels für die Formulare. Jetzt müssen Sie die Links zu dem Kontaktformular ändern. Das Kontaktformular war bei uns auf der Hauptseite in der Kopfzeile im Button verlinkt. Ändern Sie diese Zeile wie folgt: Kontakt
Das Gleiche gilt für die Verlinkung in der Linkliste der Hauptseite: - Kontakt
Nachdem Sie die Änderungen vorgenommen, auf dem Server gespeichert und die Webanwendung auf dem iPhone oder iPod touch neu geladen haben, sehen Sie folgendes Verhalten: Nach dem Antippen von Kontakt lädt das Gerät die Informationen, die in der Datei form.html enthalten sind. Normalerweise würde der Browser bei einem derartigen Link eine neue Webseite aufrufen. Mit jQTouch bleibt aber der alte Bildschirm so lange bestehen, bis die Informationen aus form.html geladen sind. Sobald das geschehen ist, wird mit der eingestellten Animation zum neuen Bildschirm gewechselt. jQTouch hat es Ihnen damit ermöglicht – auch ohne eine einzige Zeile JavaScript zu programmieren –, AJAX-Verhalten in Ihre Webanwendung zu integrieren. Wenn Sie wieder zurück auf den Hauptbildschirm gehen und nochmals auf Kontakt tippen, werden Sie bemerken, dass jQTouch die Daten im Cache gespeichert hat und sie daher nicht nochmals geladen werden müssen.
1.5
HTML und Telefonfunktionen
Von HTML aus können Sie einfach und effektiv einige Telefonfunktionen ansprechen. Manche, wie beispielsweise die Implementierung einer Landkarte, lassen sich eleganter mit JavaScript und der Google Maps-API realisieren, allerdings ist das auch wesentlich aufwendiger. Viele Telefonfunktionen wie beispielsweise die Kamera, das Adressbuch
68
Kapitel 1 – Mobile Designprinzipien
oder auch der Kalender, lassen sich noch nicht vom Browser aus ansprechen. Zum Zeitpunkt der Entstehung dieses Buchs hat Google zwar angekündigt, den Kamerazugriff vom Browser aus in einer zukünftigen Version von Android zu ermöglichen, allerdings ohne eine Versionsnummer oder ein Datum zu nennen. Was der Browser noch nicht kann, lässt sich jedoch mit nativen Anwendungen realisieren. Dazu aber mehr am Ende des Buchs, jetzt schauen wir erst mal, was wir alles im Webbrowser machen können.
1.5.1
Telefonnummer benutzen
Sie können von einer Webseite aus dem Benutzer direkt anbieten, eine Telefonnummer zu wählen. Das geschieht einfach über das tel-Protokoll und einen ganz normalen HTML-Link: 0351 123456789
Nach dem Antippen eines solchen Links passiert Folgendes: Bevor der Anruf ausgeführt wird, sieht der Benutzer einen kleinen Dialog und kann einem Anruf zustimmen oder ihn ablehnen. Auf einem iPod touch oder einem iPad kann der Benutzer zwar keinen Anruf tätigen, dafür aber die Telefonnummer in seinen Kontakten speichern.
Bild 1.33: Bevor der Anruf ausgeführt wird ...
Auf einem Android-Telefon wird der Telefonbildschirm eingeblendet. Entscheidet sich der Benutzer, den Anruf doch nicht durchführen zu wollen, kann er über die ZurückTaste eines Android-Telefons zurück in die Webanwendung kommen. Das iPhone versteht übrigens nicht nur Nummern: Teile des RFC 2086-Protokolls sind im mobilen Safari implementiert. Somit können beispielsweise über den Buchstaben »p« einsekündige Pausen in die Telefonnummer mit eingebaut werden. Weiterhin ist die Angabe von Buchstaben zugelassen. Unsere Tests haben allerdings gezeigt, dass diese Funktionalität – die ohnehin nicht häufig genutzt wird – nur auf dem iPhone, nicht aber auf Android-Geräten funktioniert.
1.5 HTML und Telefonfunktionen
1.5.2
69
SMS-Anwendung aufrufen
Falls Sie von Ihrer Webseite aus den Versand einer Textnachricht veranlassen möchten, können Sie den folgenden HTML-Link verwenden: Schick mir eine SMS
Auf Android-Geräten wird der Benutzer gefragt, ob er eine Textnachricht verfassen will, auf den Apple-Geräten zeigt sich folgendes Verhalten: Auf einem iPhone wird sofort von der Webseite in die SMS-Anwendung gewechselt und die Telefonnummer als Empfängernummer eingestellt. Die Meldung im rechten Bild auf einem iPod touch bzw. einem iPad, die natürlich keine SMS versenden können, ist leider suboptimal.
Bild 1.34: Links auf dem iPhone, rechts auf iPod touch oder iPad.
Noch zwei Tipps: Bei der Angabe einer SMS-Nummer dürfen Sie im Gegensatz zum tel-Protokoll nur Ziffern, Bindestriche und Punkte verwenden. Eine eigentliche Textnachricht ist leider nicht möglich. Falls Sie unterdrücken möchten, dass Safari die Ziffernfolgen, die nach Telefonnummern aussehen, automatisch als solche klassifiziert und klickbar macht, können Sie das mit folgender Zeile im head-Bereich Ihrer Webseite unterdrücken: <meta name "format detection" content "telephone no">
Das meta-Tag ist Apple-spezifisch und funktioniert bislang nicht auf anderen Browsern.
1.5.3
E-Mails versenden
Insbesondere in den frühen Tagen des Internets fand man E-Mail-Links häufig auf normalen Webseiten. Die Links mit dem mailto:-Protokoll haben dann Outlook Express oder das jeweilige Standard-E-Mail-Programm auf dem Rechner geändert. Mittlerweile, da ein großer Teil der E-Mail-Kommunikation über Webseiten abläuft, hat das mailto:-Protokoll auf Desktop-Webseiten seinen Glanz verloren, ist jedoch bei mobilen Webseiten durchaus sinnvoll, da viele Benutzer beispielsweise auf dem iPhone die eingebaute Mailanwendung verwenden, die mit dem Protokoll tadellos funktioniert.
70
Kapitel 1 – Mobile Designprinzipien
Um die E-Mail-Anwendung von einem Telefon aus aufzurufen, müssen Sie nur folgenden Link angeben: E Mail an mich
Sobald der Benutzer auf den Link tippt, schiebt sich auf einem iPhone oder einem iPod touch die Mailanwendung von unten in den Bildschirm.
Bild 1.35: Aufgerufener E-Mail-Bildschirm.
Anstatt nur eine E-Mail-Adresse anzugeben, an die die fertige E-Mail verschickt werden soll, lassen sich innerhalb des mailto:-Protokolls noch weitere optionale Angaben machen: Optionale Angaben im mailto:-Protokoll subject Text
Mit dem subject-Attribut können Sie bereits im Link eine Betreffzeile festlegen.
body Text
Über das body-Attribut kann der Inhalt einer E-Mail definiert werden. Dabei ist zu beachten, dass nur das iPhone derzeit HTML-Tags innerhalb des body-Attributs versteht und korrekt umsetzen kann. Um auch unter Android zu funktionieren, empfiehlt es sich, für Zeilenumbrüche den Code %0A%0A zu verwenden. Das iPhone hatte früher Probleme damit, kann aber mittlerweile auch diesen Code umsetzen.
cc [email protected]
Legt fest, wer die E-Mail als Kopie (CC) empfangen soll.
bcc [email protected] Legt fest, wer die E-Mail als Blindkopie (BCC) erhalten soll. [email protected], [email protected]
Mehrere Empfängeradressen werden durch Kommata getrennt angegeben.
Das folgende Beispiel enthält alle in der Tabelle vorgestellten Parameter. Der erste Parameter wird, wie in HTML üblich, mit einem Fragezeichen eingeleitet, und zusätzliche Parameter werden mit dem &-Zeichen angebunden: E Mail an mich
1.5 HTML und Telefonfunktionen
71
Bild 1.36: Die Ansicht im E-Mail-Programm auf dem iPod touch.
1.5.4
Google Maps aufrufen
Weiter unten im Buch, wenn die Geolocation-API für HTML5 untersucht wird, gehen wir detaillierter auf Google Maps und die Google Maps-API ein. Zunächst aber kommen wir zu einer sehr einfachen Möglichkeit, die Dienste des Google Maps-Programms zu nutzen. Auch hier müssen Sie kein JavaScript benutzen, sondern nur einen speziellen Link setzen. Den Rest machen die Telefone von allein. Als Beispiel verwenden wir wieder einen ganz einfachen Link. Es ist genau der gleiche Link, den Sie auch dazu benutzen können, Google Maps von jedem Webbrowser der Welt aus aufzurufen: Hier wohne ich
Wie Sie sehen, benutzt der Link das ganz normale HTTP-Protokoll für Webseiten. Da Google Maps als native Anwendung unter iOS aber schneller und besser zu bedienen ist als die Webseite, leitet ein iPhone, iPod touch oder iPad gleich auf die Anwendung weiter. Der Link wird wie jeder andere Weblink dargestellt, allerdings wird beim Anklicken der Browser in den Hintergrund gelegt und die Google Maps-Anwendung geöffnet. Sobald die Anwendung aufgerufen ist, wird der Ort gesucht, der mittels des q-Attributs in der URL angegeben wurde. Sie können dabei eine ganz normale Adresse angeben, müssen aber darauf achten, dass die Leerzeichen durch Pluszeichen ersetzt werden.
72
Kapitel 1 – Mobile Designprinzipien
Bild 1.37: Über den Link wird der Browser in den Hintergrund gelegt und die Google MapsAnwendung geöffnet.
Ähnlich ist es auch bei Android-Geräten. Hier wird der Benutzer allerdings vor dem Aufrufen der Google Maps-Anwendung vor die Frage gestellt, ob er die Karte nicht doch im Browser anzeigen lassen möchte. Wie im normalen Browser unterstützt der Aufruf der nativen Google Maps-Anwendung auch weitere (wenn auch bei Weitem nicht alle) Attribute: Attribute beim Aufruf von Google Maps +(Name+des+ Labels)
Am Ende der angegebenen Adresse kann die Bezeichnung definiert werden, die anstelle der Adresse auf der Karte angezeigt wird. Das unten stehende Beispiel bestimmt, dass anstatt 1120 Union die Bezeichnung Meine Bude verwendet wird.
t k
Die Karte wird nicht im normalen Kartenmodus, sondern mit Satellitenbildern angezeigt.
t h
Die Karte wird nicht im normalen Kartenmodus, sondern im Hybridmodus (Satellitenbilder mit Straßennamen etc.) angezeigt.
Leider werden weitere Layer wie beispielsweise Verkehrsmeldungen oder auch die zu verwendende Zoomstufe nicht mit an die Anwendung übertragen, sondern funktionieren bislang nur im Desktop-Browser nach einem Linkaufruf. Mit dem nächsten Aufruf erhalten Sie die folgende Kartenansicht: Hier wohne ich
1.5 HTML und Telefonfunktionen
73
Bild 1.38: Anstatt 1120 Union wird die Bezeichnung Meine Bude verwendet.
Neben einer einzelnen Adresse können Sie über einen etwas modifizierten Link auch den Google Maps-Routenplaner aufrufen. Unter Android wird Ihnen zusätzlich nach dem Aufruf von Google Maps die Option angeboten, Sie mittels Google-Navigation zum Ziel zu führen. Für die Routenplanung werden zwei Attribute verwendet: Attribute für die Routenplanung saddr
Die Startadresse wird mit diesem Attribut formuliert. Wie schon bei der Suchanfrage wird die Adresse ganz normal angegeben. Nur die Leerzeichen werden wieder mit Pluszeichen ersetzt.
daddr
Die Zieladresse wird mittels dieses Attributs angegeben.
Ein Beispiel: So kommen Sie von New York zu mir
Als Startadresse haben wir nur einen Stadtnamen und als Zieladresse einen Straßennamen, eine Hausnummer und einen Stadtnamen angegeben. Wird nur die Zieladresse angegeben, hat der Benutzer noch die Möglichkeit, seinen eigenen Startpunkt auszuwählen. Unser Beispiel fragt nach der Route zwischen New York und San Francisco. Mit einem Tag und 22 Stunden konstanter Fahrzeit ist Google da recht optimistisch.
Bild 1.39: Zeigt die Entfernung zwischen zwei Orten.
74
Kapitel 1 – Mobile Designprinzipien
Alle Beispiele haben wir in diesem kleinen Codebeispiel noch einmal zusammengefasst und es mit iWebKit 5 gestaltet: Adresse <meta name "layout" content "webkit" /> <meta content "minimum scale 1.0, width device width, maximum scale 0.6667, user scalable no" name "viewport" /> Markus Spiering <span class "graytitle">Telefonnummer: - So kommen Sie von New York zu mir
1.6 iPhone-spezifisch: Web Apps, die den Browser verbergen
75
Das Beispiel zeigt Ihnen alle vorgestellten Linkformate auf einer Seite, sodass Sie die Funktionen leicht auf verschiedenen Plattformen und Geräten testen können:
Bild 1.40: Beispiel der vorgestellten Linkformate.
1.6
iPhone-spezifisch: Web Apps, die den Browser verbergen
Auch wenn die vorgestellten Beispiele auf den meisten neuen Smartphones gut aussehen, geht das iPhone noch einen Schritt weiter und verwischt den Unterschied zwischen einer Webseite, die im Browser läuft, und einer richtigen App. Weiter unten im Buch werden wir noch darauf eingehen, wie man aus einem Webseitencode eine wirklich native Anwendung baut, doch auch ohne diesen Schritt und mit nur etwas zusätzlichem HTML kann der Safari-Browser ausgeblendet werden. Das iPhone und auch der iPod touch oder das iPad erlauben es, Webseiten als kleine Symbole auf dem Home-Bildschirm zu speichern. Um das zu tun, muss der Benutzer auf dem iPhone auf das kleine +-Symbol in der unteren Werkzeugleiste des SafariBrowsers klicken und Zum Home-Bildschirm auswählen. Anschließend erhält er einen Bildschirm angezeigt, in dem er den Namen des Symbols noch verändern kann. Wenn Sie keine weiteren Anpassungen an Ihrer Webseite vornehmen, wird das iPhone einen Screenshot Ihrer Seite aufnehmen, diesen verkleinern und als Symbol verwenden. Der Benutzer kann anschließend einfach auf Ihr Screenshot-Symbol auf dem Home-Bildschirm tippen und Ihre Seite aufrufen. Um wie eine richtige Webanwendung auszusehen, müsste in diesem Fall •
ein richtiges Symbol und kein Screenshot verwendet werden,
•
der Safari-Browser nicht sichtbar sein,
•
die Webanwendung sofort nach dem Antippen komplett auf dem Bildschirm erscheinen und nicht erst Element für Element geladen werden.
Die gute Nachricht: Das alles geht beim iPhone! Fangen wir mit einem richtigen Symbol an. Als Icon für Ihre Webanwendung können Sie jede Grafik nehmen, die 114 x 114 Bildpunkte groß und im PNG-Format gesichert ist (beispielsweise unter dem Namen
76
Kapitel 1 – Mobile Designprinzipien
icon114x114.png). Diese Grafik speichern Sie im Hauptverzeichnis Ihrer Webseite auf dem Server und fügen im head-Bereich Ihres HTML-Codes die folgende Zeile hinzu:
Sie können optional auch ein Piktogramm mit den Maßen 57 x 57 erstellen, was einmal die Originalgröße des iPhones war. Durch den hochauflösenden Bildschirm des iPhones 4 sieht die Variante mit 114 Bildpunkten besser aus und wird auf den älteren iPhones gut heruntergerechnet. Wenn Sie nun die Webseite auf Ihrem iPhone aufrufen und das Pluszeichen antippen, sehen Sie bereits im nächsten Bildschirm, dass Ihre neue Grafik als Symbol verwendet wird.
Bild 1.41: Eine Webanwendung wird dem Home-Bildschirm hinzugefügt. Auf dem Home-Bildschirm wird die Anwendung wie eine iPhone App dargestellt.
Um jetzt beim Start den Safari-Browser auszublenden, brauchen Sie nur folgende Zeile in den head-Bereich der Webseite einzubinden: <meta name "apple mobile web app capable" content "yes" />
Dieses meta-Tag wird ebenfalls nur von Safari für das iPhone verstanden und von anderen Browsern ignoriert, bewirkt aber, dass beim Antippen des gespeicherten Symbols nur die Webanwendung aufgerufen wird – nicht aber die Safari-Bedienflächen. Sobald der Benutzer eine Webanwendung, die mit diesem meta-Tag ausgestattet ist, auf seinem Home-Bildschirm ablegt und wieder startet, bekommt er also nicht mehr die URL-Eingabeleiste oder die Werkzeugleiste am unteren Bildschirmende des Safari-Browsers zu sehen – genau wie bei einer richtigen iPhone-Anwendung.
Bild 1.42: Die Safari-Bedienflächen sind verschwunden. Deutlich wird das, wenn man, wie hier dargestellt, die gesamte Seite nach unten zieht.
1.6 iPhone-spezifisch: Web Apps, die den Browser verbergen
77
Tipp: Es kann nun sogar mit einem bisschen JavaScript und dem standalone-Attribut des navigator-Objekts überprüft werden, ob die Webseite im Vollbildmodus angezeigt wird oder nicht: <script> if (window.navigator.standalone) alert('Wir sind im Vollbildmodus'); <script>
Sie können sogar noch etwas weitergehen und Ihren Benutzern einen kleinen Hinweis darauf geben, dass sie Ihre Web App auf den Home-Bildschirm legen können, um leichter wieder zur Seite zurückzufinden und diese dann auch im Vollbildmodus zu sehen. Das folgende Codebeispiel zeigt jeweils eine Meldungsbox, wenn die Anwendung im Vollbildmodus läuft bzw. wenn nicht: <script> if (window.navigator.standalone) { alert ('Wir sind im Vollbildmodus!') } else { alert('Tipp: Legen Sie diese Seite auf Ihren Home Bildschirm. Tippen Sie auf das Pluszeichen im Safari Browser.') }
Natürlich sollten Sie in der Praxis die Meldungsbox für den Vollbildmodus weglassen und beispielsweise ein CSS-Overlay für die Meldung verwenden, wenn die Webanwendung nicht im Vollbildmodus läuft. Die Webanwendung fühlt sich bereits viel mehr nach Anwendung an, allerdings gibt es noch einen großen Unterschied: Nach dem Antippen und Starten einer nativen Anwendung wartet man nicht ein paar Sekunden, bis alle Bildschirmelemente geladen sind. Typisch für iPhone-Anwendungen ist der sogenannte Startup-Bildschirm, der meistens so lange eine schön designte Grafik zeigt, bis alle Daten initialisiert und geladen sind. Mit nur einem weiteren HTML-Tag im head-Bereich der Seite lässt sich das genau so bei einer Webanwendung integrieren. Sie benötigen dazu wieder eine Grafik bzw. Bilddatei im PNG-Format, die das Format 320 x 460 oder 640 x 960 Bildpunkte (iPhone 4) besitzen muss. Wie bei der eben beschriebenen Symboldatei kann das PNG auch in 24Bit-Farbtiefe vorliegen. Nennen Sie die Datei beispielsweise splash320x240.png, und fügen Sie folgendes HTML-Tag in den Code ein:
Ab sofort wird nach dem Antippen des Symbols auf dem Home-Bildschirm genau diese Grafik angezeigt und erst nach wenigen Augenblicken entfernt, wenn die komplette Webseite geladen ist und dargestellt wird.
78
Kapitel 1 – Mobile Designprinzipien
Bild 1.43: Dieser Startup-Bildschirm wird so lange angezeigt, bis alle Seitenelemente vollständig geladen sind.
Die Startzeit kürzer erscheinen lassen Ein Trick, um die Startzeit Ihrer Anwendung kürzer erscheinen zu lassen, ist, ein identisches »Bild« der Anwendung als Startup-Bildschirm zu benutzen. Wenn Sie einmal genau in den App Store oder sogar auf Ihrem iPhone in die YouTube-Anwendung schauen, sehen Sie, was wir meinen. Bei der Auswahl oder Modifikation des Screenshots müssen Sie darauf achten, dass sich keine Linien oder Elemente verschieben und – wesentlich wichtiger – keine Elemente antippbar erscheinen. Hier zwei Beispiele Die Flickr-iPhone-Anwendung benutzt einen Startbildschirm, in dem die Kopfleiste mit dem Flickr-Logo bereits sichtbar ist, der eigentliche Inhalt in der Mitte aber noch fehlt. Auch auf die Buttons am unteren Rand wurde verzichtet, da der Benutzer sie sonst versehentlich auf dem Bild benutzen könnte. Sobald die Anwendung vollständig geladen ist, wird der Inhalt in der Mitte geladen, und die Navigationselemente werden eingeblendet.
Bild 1.44: Startbildschirm der FlickriPhone-Anwendung.
Ähnlich sieht es bei Facebook aus. Die Aufteilung der Anwendungsoberfläche wird bereits nach dem Start über ein statisches Bild sichtbar, das auch schon das Logo verwendet. Ist die Anwendung geladen, werden die zusätzlichen und antippbaren Elemente angezeigt. Bei der deutschen Version verschiebt sich das Logo, was in der englischen Originalversion nicht der Fall ist. Statt des langen Worts Live-Meldungen wird einfach Live Feed verwendet, was den Button nicht zu groß werden lässt.
1.6 iPhone-spezifisch: Web Apps, die den Browser verbergen
79
Bild 1.45: Startbildschirm der Facebook-Anwendung.
Standardmäßig besitzt jede iPhone-Anwendung eine Kopfzeile. Diese hat einen grauen Hintergrund und ist der Bereich, in dem beispielsweise der aktuelle Netzbetreiber, die Uhrzeit und der Akkuladestand angezeigt werden. Insbesondere für Webanwendungen, die nach richtigen Anwendungen aussehen sollten, lässt sich das konfigurieren und passt damit eher beispielsweise zu einem schwarzen, modernen Seitendesign. Um die Kopfzeile zu ändern, geben Sie eine der folgenden Zeilen im head-Bereich der Seite ein: Für eine schwarze Kopfzeile: <meta name "apple mobile web app status bar style" content "black"/>
Für eine dunkle, aber transparente Kopfzeile: <meta name "apple mobile web app status bar style" content "black translucent"/>
Für die standardmäßig graue Kopfzeile: <meta name "apple mobile web app status bar style" content "default"/>
1.6.1
Startup-Bildschirm und App-Icon mit jQTouch
Falls Sie ohnehin mit der vor einigen Seiten vorgestellten JavaScript- und CSS-Bibliothek jQTouch arbeiten, können Sie den Startup-Bildschirm und das App-Icon gleich dort mitdefinieren, wo Sie auch die jQTouch-Funktionen initialisieren. Mit diesen drei Extrazeilen wird genau das erreicht, was wir eben mittels der CSS-Methoden beschrieben haben: <script type "text/javascript"> var jQT $.jQTouch({ icon: 'apple touch icon.png', statusBar: 'black translucent', startupScreen: 'startup bildschirm.png' });
80 •
Kapitel 1 – Mobile Designprinzipien
icon: Legt ein Piktogramm für die Webanwendung fest, wenn der Benutzer sie auf dem Home-Bildschirm speichert. Als Icon wird die hinter icon: stehende PNG-
Datei verwendet. •
statusBar: Die Statuszeile wird in diesem Fall schwarz transparent gesetzt. Alternativ ist hier noch black möglich. Wird dieser Parameter nicht spezifiziert, wird die Standardstatuszeile in Grau verwendet.
•
startupScreen: Die hinter dem Parameter stehende Bilddatei wird als StartupBildschirm verwendet und so lange angezeigt, bis die Webanwendung vollständig geladen ist.
1.6.2
CSS-Gestaltung für Hoch- und Querformat
Bei vielen iPhone-Anwendungen und auch bei einigen wenigen mobilen Webseiten ist es üblich, dass sie gezielt ihr Aussehen nach der Ausrichtung des Telefons ändern, je nachdem ob der Benutzer es im Hoch- oder im Querformat hält. Im head-Bereich einer HTML-Datei können Sie mit den folgenden Anweisungen unterschiedliche CSS-Dateien für die jeweilige Bildschirmausrichtung zuweisen:
Das CSS-orientation-Attribut funktioniert auf der iOS-Plattform ab iOS 4.0 für den iPod touch und das iPhone sowie für das iPad ab Version 3.2. Auch Telefone mit Android-Betriebssystem verstehen es. Am besten lässt sich diese Funktionalität wieder anhand eines kleinen Beispiels verdeutlichen. Wir erstellen eine einfache mobile Seite, die im Hochformat ein kleineres Bild auf weißem Hintergrund anzeigt und im Querformat das gleiche Bild lädt, es aber auf einem schwarzen Hintergrund größer darstellen soll. Zuerst erstellen Sie die CSSZuweisungen für die Hochformatansicht in der Datei portrait-style.css: body
{ color: black; background-color: #ffffff; font family: Arial; font size: 12px;
} #imageContainer { background: url('stairs.jpg') no repeat top center; height: 240px; width: 320px; }
Setzen Sie am Anfang den ganzen body-Bereich in einen weißen Hintergrund, und nehmen Sie die üblichen Schriftzuweisungen vor. Weiterhin legen Sie ein ID-Attribut #imageContainer an, das nicht nur die Bilddatei enthält, sondern auch die Höhe und Breite des anzuzeigenden Bilds definiert. Das Gleiche machen Sie noch einmal in der Datei landscape-style.css, allerdings mit etwas geänderten Werten:
1.6 iPhone-spezifisch: Web Apps, die den Browser verbergen
body
81
{ color: white; background-color: #000000; font family: Arial; font size: 12px;
} #imageContainer { background: url('stairs.jpg') no repeat top center; height: 267px; width: 400px; }
In der Datei landscape-style.css setzen Sie die Hintergrundfarbe auf Schwarz und sorgen auch mittels der height- und width-Attribute für eine größere Darstellung des Bilds. Der HTML-Code für das kleine Beispiel: Rotationsbeispiel <meta name "viewport" content "width device width; initial scale 1.0; maximum scale 1.0; user scalable 0;" />
Das Ergebnis ist: Hält der Benutzer sein Telefon hochkant, wird nur ein kleines Bild geladen und auf weißem Hintergrund dargestellt. Sobald der Benutzer sein Telefon in das Querformat dreht, wechselt sofort die Hintergrundfarbe, und das Bild wird wesentlich größer dargestellt.
Bild 1.46: Die Ansicht im Hoch- und im Querformat.
82
Kapitel 1 – Mobile Designprinzipien
Alternativ: doppelte CSS-Verweise im HTML-Code Es gibt einen Trick, mit dem es sich am Anfang besser arbeiten lässt, vor allem dann, wenn Sie nicht zwei komplett unterschiedliche CSS-Varianten pflegen und dazu noch unterschiedliche Dateien in den jeweiligen Ansichten verwenden wollen. Auch bei diesem Alternativvorschlag verwenden wir die oben genannten Verweise auf die beiden CSS-Dateien. Allerdings sieht deren Inhalt nun anders aus. Für die Datei portrait-style.css verwenden Sie jetzt folgende Definitionen: body
{ color: black; background color: #ffffff; font family: Arial; font size: 12px;
} #landscape {display:none}
Führen Sie hier die ID-Zuweisung #landscape ein, und definieren Sie im CSS, dass, wenn diese ID im HTML-Code verwendet wird, dieser HTML-Code nicht angezeigt werden soll. Genau das Gleiche, aber umgekehrt, machen Sie für die Datei landscapestyle.css: body
{ color: white; background color: #000000; font family: Arial; font size: 12px;
} #portrait {display:none}
Dreht der Benutzer sein Telefon in die horizontale Richtung und wird die Datei landscape-style.css für die Darstellung benutzt, werden alle mit der ID portrait versehenen Elemente im HTML-Code nicht angezeigt. Auch der HTML-Code muss etwas angepasst werden: Rotationsbeispiel ...
Verwenden Sie einfach zwei img-Tags auf einer Seite. Ein Tag wird mit Sicherheit ignoriert, da Sie das ja in den CSS-Definitionen festgeschrieben haben. Der Vorteil bei dieser Variante liegt darin, dass Sie genau steuern können, welche HTML-Elemente in der jeweiligen Ansicht sichtbar sein sollen und welche nicht.
83
2
HTML5 in der mobilen Webentwicklung
In diesem Kapitel erwartet Sie die technische Vorstellung der wichtigsten Neuerungen und Änderungen rund um HTML5. Wie Sie bereits wissen, war der Umfang der HTML5-Spezifikation häufigen Änderungen unterworfen, und somit hat sich in den Medien ein etwas konfuses Bild des Umfangs der HTML5-Spezifikation gebildet. Da APIs wie beispielsweise die Geolocation-API, genau genommen nicht in den Umfang der HTML5-Spezifikation gehören, die darin enthaltenen Features rund um die Ortung von Geräten jedoch gerade für die mobile Webapplikationsentwicklung immens wichtig sind, wird das ebenfalls in diesem Kapitel behandelt. Weil der Umfang dieses Buchs jedoch beschränkt ist und sich viele hier besprochene Spezifikationen leider noch nicht im finalen Stadium befinden, konzentrieren wir uns auf die für die mobile Webentwicklung relevanten und derzeit implementierten Features. Um die Beispiele in diesem Kapitel verstehen zu können, müssen die Grundlagen der Webentwicklung und die damit verknüpften Technologien wie HTML, CSS und JavaScript verstanden werden. Der folgende Abschnitt erklärt diese Technologien nicht von Grund auf, sondern stellt die neuen, relevanten Funktionen und Möglichkeiten vor. Download http://www.buch.cd Um die Codebeispiele in diesem Kapitel strukturiert überprüfen zu können, wurde eine kleine mobile Webanwendung erstellt, die Sie über die Seite zum Buch abrufen können.
2.1
Von HTML 4 nach HTML5
HTML5 definiert zwei Schreibweisen, die sogenannte HTML-Schreibweise und eine XML-konforme Schreibweise.
2.1.1
Syntaktische Unterschiede
Diese beiden Schreibweisen erläutern wir am besten anhand von kurzen Beispielen. Betrachten wir zunächst die HTML-Schreibweise: <meta charset "UTF 8"> Beispiel HTML5 Schreibweise
84
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Ein Paragraf
Auffallend neu ist zunächst die erste Zeile, die ungewohnt kurz erscheint. Auf den HTML5-doctype, der nur bei der HTML-Schreibweise vorgeschrieben ist, werden wir im nächsten Abschnitt noch näher eingehen. Kurz gefasst, teilt er dem Browser mit, dass die standardkonforme Darstellung der HTML-Seite benutzt werden soll. Mit dem HTML 4-doctype-Hell ist damit ein für alle Mal Schluss. Der HTTP-Content-Type, der bei der HTML-Schreibweise benutzt werden sollte, ist doctype/html.
Mit Ausnahme des neuen doctype ist bei dem obigen Beispiel noch anzumerken, dass – im Unterschied zur XML-Schreibweise – manche Tags nicht zwingend geschlossen werden müssen. Die folgende Zeile aus dem HTML-Beispiel ist kein Fehler, sondern korrektes HTML5 nach der HTML-Schreibweise: <meta charset "UTF 8">
Beachten Sie, dass das Tag frei steht und nicht geschlossen ist. Es ist nicht XML-konform, da kein geschlossenes Tag vorhanden ist, jedoch korrektes HTML5. Die zweite Syntax, die HTML5 definiert, ist die XML-Schreibweise. Das HTML-Dokument muss hierbei XML-konform sein, also beispielsweise muss jedes öffnende Element ein entsprechendes schließendes Element haben: Beispieldokument Beispielabsatz
Das Encoding wird hierbei auch durch die XML-Deklaration in der ersten Zeile angegeben und nicht per meta-Tag wie bei der HTML-Schreibweise. Ebenso wichtig ist, dass der XHTML-Namespace durch das xmls-Attribut des HTML-Tags angegeben werden sollte. Der Content-Type, der für die XML-konforme Schreibweise benutzt werden sollte, ist application/xhtml+xml oder application/xml. Beachten Sie auch, dass der HTML5-doctype hier nicht mehr benötigt wird, da die standardkonforme Darstellung der HTML-Seite die XML-Schreibweise impliziert. In der Realität müssen wir feststellen, dass viele HTML-Autoren die XML-Schreibweise vorziehen, diese HTML-Dokumente jedoch selten mit application/xml-ContentType vom Webserver ausgeliefert werden. Ebenso ist der doctype bei Benutzung der XML-Schreibweise nicht notwendig, er wird aber dennoch von vielen Autoren benutzt.
2.2 Sprachliche Unterschiede
85
Glücklicherweise scheinen die aktuellen Browser, die zunehmend HTML5-Features beherrschen, damit überaus gnädig umzugehen.
2.1.2
Character Encoding
Bei Benutzung der HTML-Syntax haben die Autoren mehrere Möglichkeiten, das Character-Encoding anzugeben: •
Auf der Transportebene durch den HTTP-Content-Type-Header.
•
Durch die Benutzung eines meta-Elements und dessen charset-Attribut.
Für die XML-Syntax gelten die üblichen XML-Regeln, also beispielsweise die Deklaration des Encodings in der XML-Deklaration, wie im XML-Beispiel demonstriert.
2.1.3
Der !doctype html
Der !doctype html ist lediglich bei der HTML-Schreibweise vorgeschrieben und hat den einzigen Zweck, dem Browser mitzuteilen, die standardkonforme Darstellung der HTML-Seite zu benutzen. Bei der XML-Schreibweise ist er komplett überflüssig, da die Benutzung dieser Schreibweise bereits die standardkonforme Darstellung impliziert. Die noch unter HTML 4 umständliche und lange Schreibweise des doctype ist nicht mehr erforderlich. Verwenden Sie daher für Seiten, die HTML5 nutzen, als erste Zeile im Code immer:
2.2
Sprachliche Unterschiede
Die sprachlichen Unterschiede zu HTML 4 werden in den folgenden Absätzen erläutert. HTML5 definiert zahlreiche neue Elemente und neue Attribute für bestehende Elemente, verändert die Bedeutung bestehender Elemente und verwirft Attribute oder Elemente. An dieser Stelle soll nur ein kurzer Überblick über die wichtigsten Neuerungen gegeben werden. Diese Ausführungen können also eine HTML5-Referenz nicht ersetzen. Allen voran stehen neue Elemente in HTML5, die HTML eine bessere Struktur geben. Dazu gehören Elemente wie section, article, aside sowie die header- und footerElemente. Oftmals lösen sie div-Elemente ab, die per id-Attribut eindeutig in der HTMLSeite referenziert werden konnten. Der Vorteil dieser neuen Elemente liegt darin, dass sie tatsächlich über den Inhalt eine Aussage machen. Damit wird eine maschinelle Auswertung des Inhalts überhaupt erst möglich. Betrachten wir einige neue Elemente: • • • • • •
article aside hgroup header footer nav
86 •
Kapitel 2 – HTML5 in der mobilen Webentwicklung
figure/figcaption
Weitere neue Elemente, die nicht sprachlicher Natur sind, sondern konkret neue Features in HTML5 ermöglichen, sind: • • • • •
audio und video (inklusive source-Element) canvas time details/summary output
Für das input-Element werden zahlreiche neue Werte des type-Attributs definiert. Dadurch hat der Browser die Möglichkeit, die Darstellung dieser Elemente je nach Typ zu optimieren. Zu den derzeit im iPhone unterstützten Typen gehören beispielsweise tel, url, email und number. Im Fall eines
wird dem Benutzer keine komplette Tastatur präsentiert, sondern nur ein Ziffernblock. Die Eingabe der Daten durch den Nutzer wird dadurch natürlich deutlich vereinfacht. Ebenso wurden bestehenden HTML-Elementen zahlreiche neue Attribute hinzugefügt: •
Das a-Element hat nun ein ping-Attribut, das die URL zu einem Tracking-Pixel enthalten kann. Tracking-Pixel sind üblicherweise GIF-Bilder, die 1 x 1 Pixel groß und transparent sind. Diese Pixel werden dazu verwendet, Werbeeinblendungen oder Aktionen des Benutzers zu verfolgen. Der Browser fordert das definierte Pixel an, bevor der eigentliche Link aufgerufen wird.
•
Ein äußerst praktisches neues Merkmal des input- und textarea-Elements ist das Attribut placeholder. Sicherlich haben Sie auch schon JavaScript geschrieben, um einen Platzhaltertext innerhalb eines input-Elements zu platzieren, wenn dieses Element keinen Inhalt hat. Das placeholder-Attribut macht diesen JavaScriptCode nun überflüssig.
•
Das input-Element hat jetzt ebenfalls zahlreiche neue Attribute, um weitere Einschränkungen zu definieren. Dazu gehören die Attribute min, max, pattern und step.
•
Ganz neu in HTML5 sind die sogenannten Offline Web Applications. Es wird später noch genauer darauf eingegangen. Kurz gefasst, kann eine gewöhnliche HTML-Seite damit offline, also komplett ohne Internetverbindung, weitergenutzt werden, da sämtliche Ressourcen dieser Seite auf dem Client gespeichert werden.
•
Das iframe-Element hat drei neue Attribute: sandbox, seamless und srcdoc. Dadurch lässt sich definieren, welchen Zugriff das enthaltene HTML-Dokument auf die Hostseite erhält – praktisch für Blog-Kommentare. Um hier zu verhindern, dass ein eingeschleustes Stück JavaScript mit der Hostseite Unfug treibt, kann das entsprechend restriktiv belegt werden. Die iframe-HTML-Seite hat damit keinen Zugriff auf die umgebende HTML-Seite.
Des Weiteren sind nun bekannte Attribute aus HTML 4 zu globalen Attributen gemacht worden. Die Attribute class, dir, id, lang, style und tabindex sind jetzt in jedem Element vorhanden.
2.2 Sprachliche Unterschiede
87
Es wurden auch neue globale Attribute definiert. Dazu gehören unter anderem: • • • •
contenteditable draggable hidden spellcheck
Zu den nicht mehr empfohlenen Attributen zählen beispielsweise das border-Attribut des img-Elements und das language-Attribut des script-Elements. Der Rahmen eines Bilds kann besser über CSS definiert werden, und der Wert des language-Attributs des script-Tags muss nun, wenn vorhanden, JavaScript sein. Zu den gänzlich entfernten Elementen gehören basefont, center und font sowie alle frame-Elemente. Diese können entweder besser über CSS-Styles ausgedrückt werden oder haben mehr Verwirrung als Nutzen gestiftet. Zur letzteren Kategorie gehört auch das applet-Tag, durch das kleine Java-Programme eingebunden werden konnten. Das object-Tag macht dessen Benutzung überflüssig.
2.2.1
Neue APIs
HTML5 definiert auch zahlreiche neue APIs, die über JavaScript zugänglich sind. Nachfolgend werden ein paar der APIs kurz erläutert: •
Eine API für die audio- und video-Tags ermöglicht die Kontrolle der Medien.
•
Die ApplicationCache-API ermöglicht es, offline Webapplikationen programmatisch zu kontrollieren. Beispielsweise kann festgestellt werden, ob eine Applikation gecacht wurde oder ob die Ressourcen derzeit noch gespeichert werden.
•
Es wird auch eine API definiert, durch die Webapplikationen für bestimmte Protokolle und Medientypen registriert werden können. Eine webbasierte E-Mail-Applikation kann dadurch als Standardprogramm für E-Mail verwendet werden.
•
In Verbindung mit dem contenteditable-Attribut wird eine API definiert, durch die das Editieren des Inhalts von Elementen kontrolliert werden kann.
•
Die HTML5-Drag & Drop-API definiert, wie die beliebten Drag & Drop-Operationen auf Webapplikationen konform umgesetzt werden können. Dadurch wird auch die Drag & Drop-Interaktion mit browserexternen Programmen definiert.
•
Schließlich wird auch eine API definiert, durch die die History des Browsers per JavaScript zugänglich gemacht wird. Dadurch wird es AJAX-Applikationen ermöglicht, die Probleme mit dem Zurück-Button zu lösen.
2.2.2
Neue Input-Typen, Auto-Korrektur und Auto-Großschreibung
HTML5 definiert für das input-Element zahlreiche neue Werte des type-Attributs, darunter beispielsweise url, email, number und tel. Der Großteil der komplexeren Typen wie datetime oder range werden leider noch nicht von aktuellen Browsern umgesetzt, auf iPhone OS sind jedoch immerhin folgende Typen verfügbar und werden von der UI entsprechend unterstützt:
88 • • • •
Kapitel 2 – HTML5 in der mobilen Webentwicklung
url email tel number
Die folgende Tabelle zeigt, wie auf iPhone OS derzeit die Tastaturen dieser Typen definiert sind. Generell wird die Tastatur so angepasst, dass der Nutzer die einzugebenden Daten leichter als mit der Standardbelegung der Tastatur eintippen kann. iPhone-Tastaturbelegung nach input-Type
Sowohl von Android als auch von iPhone OS wird das placeholder-Attribut unterstützt, wodurch ein Platzhaltertext für ein leeres input-Element angegeben werden kann. Sobald der Benutzer in das Feld klickt, verschwindet der Platzhalter, und die Eingabe kann stattfinden. Die automatische Korrektur der Eingaben und die automatische Großschreibung nach Punkt, Doppelpunkt, Fragezeichen und Ausrufezeichen sind leider wiederum nur auf dem iPhone OS implementiert.
Bild 2.1: Automatische Korrektur beim iPhone.
Um die automatische Korrektur einzuschalten oder explizit auszuschalten, kann das autocorrect-Attribut des input-Elements benutzt werden:
2.2 Sprachliche Unterschiede
89
Um die Großschreibung zu steuern, wird das Attribut autocapitalize benutzt. Ein normales input-Element vom Typ text hat die automatische Großschreibung standardmäßig aktiviert, um sie also explizit auszuschalten, schreiben Sie:
Neben diesen neuen Typen und größtenteils iPhone-spezifischen Attributen ist leider recht wenig der HTML5-Spezifikation in diesem Bereich implementiert. Komplexere Typen wie datetime, die vom Browser in Datumseingabefelder umgesetzt werden könnten, sind beispielsweise weder auf dem iPhone noch im WebKit-Browser auf Android implementiert. Auch viele der neuen Attribute, durch die beispielsweise die Validierung der Eingaben vorgenommen werden können (über das pattern-Attribut sollte ein regulärer Ausdruck angegeben werden können etc.), werden nicht unterstützt. Sicherlich wird sich die Lage mit der Zeit bessern, derzeit verzichten wir jedoch auf eine weitere Vorstellung dieser Features und nutzen den Platz in diesem Buch für diejenigen, die tatsächlich funktionieren. Das folgende Beispiel ruft alle derzeit verfügbaren input-Types auf:
HTML5 Input Typen / Eingabefelder Markus Spiering / Sven Haiges
> HTML5 Eingabefelder <meta name "layout" content "webkit" /> <meta content "minimum scale 1.0, width device width, maximum scale 0.6667, user scalable no" name "viewport" /> <script> (function my() { var $i {}; $i.init function() { var detectionNode, msg '', formats, pos, audio; }; document.addEventListener("DOMContentLoaded", $i.init, false); }).call(); Neue Input Typen
90
Kapitel 2 – HTML5 in der mobilen Webentwicklung
-
-
-
-
-
-
-
-
-
- <span class "name">Checkbox
- <span class "name">A
- <span class "name">B
-
-
-
2.3 Das canvas-Element
Powered by iWebKit
2.3
Das canvas-Element
Das HTML5-canvas-Element erlaubt das programmatische Erstellen von Bitmapbasierten Grafiken. Nachdem ein canvas-Tag in die HTML-Seite eingefügt worden ist, kann es per JavaScript angesprochen werden, und es kann darauf gezeichnet werden. Das canvas-Element und die damit on-the-fly erstellbaren Grafiken können für eine Vielzahl von Anwendungsfällen nützlich sein: •
Eine Finanzapplikation kann nahezu in Echtzeit die aktualisierten Chartdaten per AJAX vom Server abrufen. Mit den erhaltenen Daten wird ein Aktienchart aktualisiert. Anstatt die Bilddaten auf dem Server zu rendern und die Bilder abzurufen, müssen nur die Daten übertragen werden, das Rendern erledigen die HTML5Clients (die Browser). Der Server wird dadurch entlastet, weniger Bandbreite wird verbraucht, und die Aktualisierung der Daten geht schneller.
•
Ein Jump & Run-Spiel rendert den kompletten Spielscreen per HTML5-canvas-Element. Dieser Anwendungsfall wird durch das canvas-Element überhaupt erst ermöglicht oder war mit bisherigen Mitteln nur schwer zu erreichen.
•
Eine Zeichenapplikation nimmt vom Benutzer Maus- und Tastaturkommandos entgegen und setzt sie auf einem Canvas um. Das erstellte Bild kann im Browser dank SQL Storage gespeichert werden, die Applikation kann offline voll genutzt werden.
Die Möglichkeiten sind (fast) unbegrenzt. Aus mobiler Sicht ist das canvas-Element doppelt interessant, da wir im mobilen Bereich zum einen nicht immer auf eine beständige Internetverbindung setzen können. Des Weiteren sind die Verbindungen immer noch langsam, zudem wird oft nutzungsabhängig abgerechnet. Um den Nutzer der
92
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Applikation nicht mit der nächsten Rechnung böse zu überraschen, sollte eine mobile Webapplikation intelligenter mit den vorhandenen Ressourcen umgehen. In diesem Unterkapitel werden die Grundlagen und Features des canvas-Elements anhand vieler kleiner Beispiele vorgestellt. Die Beispiele (inklusive der vielen Grafiken) sollen es Ihnen ermöglichen, einen raschen Überblick zu bekommen, um selbst abschätzen zu können, inwiefern Sie das canvas-Element für eigene Projekte benutzen können. Genug der vielen Worte, jetzt wird gezeichnet! Das folgende Beispiel zeigt, wie einfach ein canvas-Element in eine HTML5-Seite eingebunden wird: Ihr Browser unterstützt kein HTML5 Canvas!
Einfach, oder? canvas hat nur zwei Attribute, width und height. Standardmäßig sind diese mit 300 (Breite) und 150 (Höhe) gesetzt. Der Inhalt des canvas-Elements ist der sogenannte Fallback-Content. Er wird nur angezeigt, wenn der darstellende Browser kein canvas-Element unterstützt. Ein so erstelltes canvas-Element sieht im Browser dann so aus:
Bild vergessen? Nein. Ein Canvas ist zunächst leer, d. h. vollständig transparent. Um die Fläche des Canvas sichtbar zu machen, kann er jedoch wie jedes andere HTML-Element per CSS gestylt werden.
Im obigen Beispiel wurde auch gleich ein id-Attribut hinzugefügt, damit wir das Element später aus JavaScript ansprechen können. Der Canvas sieht nun so aus:
Bild 2.2: canvas mit id-Attribut.
Jetzt können wir per JavaScript auf den Canvas zugreifen und darauf zeichnen. Das folgende Beispiel, das wir gleich Zeile für Zeile durchgehen, zeichnet zehn Quadrate mit unterschiedlichen Füllungen auf den Canvas:
2.3 Das canvas-Element
93
Bild 2.3: Auf dem Canvas zeichnen. Canvas Demos <script> function run() { var canvas document.getElementById('myCanvas'); var ctx canvas.getContext('2d'); for (var i 0; i < 10; i++) { var color Math.round((i/9) * 255); ctx.fillStyle "rgb("+color+","+color+","+color+")"; ctx.fillRect (i*30, 60, 30, 30); } } document.addEventListener("DOMContentLoaded", run, false); Ihr Browser unterstützt kein HTML5 Canvas!
Das canvas-Element im Body der Seite ist uns schon bekannt. Da wir width und height nicht weiter angegeben haben, wird der Canvas standardmäßig 300 x 150 Pixel groß sein. Wirklich spannend wird es im JavaScript-Teil dieser Seite. Zunächst wird ein Event-Listener für das DOMContentLoaded-Event registriert. Dadurch wird unsere Funktion run aufgerufen, sobald der DOM-Tree (Document Object Model) der Seite vollständig verfügbar ist. Die ersten beiden Zeilen der Funktion greifen dann auf das canvas-Element und dessen Kontext zu: var canvas document.getElementById('myCanvas'); var ctx canvas.getContext('2d');
Der Context, genau gesagt ein CanvasRenderingContext2D, ist das Objekt, das zum Zeichnen innerhalb des Canvas benutzt wird. Die HTML5-Spezifikation schreibt lediglich die Implementierung eines 2-D-Inhalts vor. Um auf dem nun referenzierten Inhalt zu zeichnen, setzen wir Eigenschaften des referenzierten Inhalts und rufen dessen Methoden auf – im Beispiel legen Sie die aktuell
94
Kapitel 2 – HTML5 in der mobilen Webentwicklung
benutzte Füllfarbe dynamisch innerhalb der for-Schleife fest und erzeugen so pro Durchgang einen unterschiedlichen Grauwert. Im nächsten Schritt wird ein Quadrat mit den Maßen 30 x 30 an dynamischer x-Position (je nach Durchgang also 0, 30, 60, 90 etc.) und an statischer y-Position 60 gezeichnet. Der Ursprung für alle Operationen ist dabei immer die obere linke Ecke des Canvas. ctx.fillStyle "rgb("+color+","+color+","+color+")"; ctx.fillRect (i*30, 60, 30, 30);
Da wir mit der Füllfarbe rgb(0,0,0) beginnen und bei rgb(255,255,255) enden, werden durch die zehn Durchgänge der Schleife zehn Quadrate in unterschiedlichen Graustufen aneinandergereiht. Unter Zuhilfenahme des CSS-Frameworks iWebKit können Sie mit leicht modifiziertem Code das Beispiel wie folgt für ein iPhone oder Android-Telefon umsetzen: Mobile Canvas <meta content "minimum scale 1.0, width device width, maximum scale 0.6667, user scalable no" name "viewport" /> <meta name "layout" content "webkit" /> <script> function init() { var canvas document.getElementById('myCanvas'); var ctx canvas.getContext('2d'); for (var i 0; i < 10; i++) { var color Math.round((i/9) * 255); ctx.fillStyle "rgb("+color+","+color+","+color+")"; ctx.fillRect (i*28, 61, 28, 28); } // Funktioniert auf dem iPhone ab 3.1 var dataURL canvas.toDataURL(); var img document.createElement('img'); img.setAttribute('src', dataURL); document.getElementById('box').appendChild(img); // Funktioniert in FF, bislang aber noch nicht auf iPhone/Android 2.2 var imageData ctx.getImageData(0,0,280,150); document.getElementById('message').innerHTML data.width + '/' + data.height; } document.addEventListener("DOMContentLoaded", init, false);
2.3 Das canvas-Element
95
Einfacher Canvas
Bild 2.4: Ein einfacher Canvas unter iOS 4.
Die folgenden Abschnitte stellen Ihnen Schritt für Schritt die Methoden und Konzepte des HTML5-Canvas vor, sind aber keineswegs als vollständige und umfassende Einführung gedacht, denn das würde ein eigenes Buch füllen. Dennoch werden die meisten und wichtigsten Features des HTML5-Canvas vorgestellt, um Ihnen einen guten Überblick zu geben. Der Canvas aller Beispiele hat eine Breite von 280 Pixeln und eine Höhe von 300 Pixeln. Die Variable ctx referenziert in allen Beispielen den 2-D-Kontext des Canvas: var canvas document.getElementById('myCanvas'); var ctx canvas.getContext('2d'); ... Beispielcode ...
96
Kapitel 2 – HTML5 in der mobilen Webentwicklung
2.3.1
Formen und Pfade
Das HTML5-canvas-Element unterstützt nur eine primitive Form: das Rechteck. Alle anderen Formen wie beispielsweise Kreise oder zusammengesetzte Formen werden durch Pfade gezeichnet und dann gefüllt. Die Canvas-API stellt uns drei Methoden speziell für Rechtecke zur Verfügung: void clearRect(in float x, in float y, in float w, in float h); void fillRect(in float x, in float y, in float w, in float h); void strokeRect(in float x, in float y, in float w, in float h);
Die Parameter dieser drei Methoden haben die gleiche Bedeutung: x und y geben die Position relativ zur oberen linken Ecke des Canvas an. Die Parameter w und h geben die Breite und Höhe der rechteckigen Fläche an. Um den Canvas zu löschen – entweder komplett oder teilweise –, bietet sich die Methode clearRect() an. Nehmen wir einen Canvas mit den Maßen 100 x 100 an, würde der folgende Aufruf somit die Fläche des Canvas komplett löschen. clearRect(0,0,100,100);
Was zurückbleibt, ist eine transparente Fläche. Wenn also der Hintergrund des Canvas – beispielsweise durch eine zugewiesene Hintergrundfarbe im der HTML-Seite – eingefärbt ist, wird die Farbe des Hintergrunds durchgereicht. Um ein nicht gefülltes Rechteck zu zeichnen, also ein Rechteck, das nur durch die äußeren Randlinien erkennbar ist, wird die Methode strokeRect() benutzt; um dieses Rechteck gefüllt auf den Canvas zu zeichnen, die Methode fillRect(). Das nächste Codebeispiel demonstriert diese drei Methoden, das Resultat ist in der folgenden Abbildung zu sehen: ctx.fillStyle "rgb(255,0,0)"; ctx.fillRect(10, 10, 260, 30); ctx.strokeStyle "rgb(0,255,0)"; ctx.strokeRect(10, 50, 260, 30); ctx.clearRect(20, 20, 100, 10);
Um Formen durch Pfadfunktionen zu zeichnen, gibt die Canvas-API folgende Methoden vor: void void void void void
beginPath(); closePath(); fill(); stroke(); clip();
Auf die clip()-Methode wird als Letztes in diesem Abschnitt eingegangen, zunächst ist es wichtig, die vier anderen Methoden zu verstehen. Um einen Pfad zu zeichnen, muss zunächst die Methode beginPath() aufgerufen werden. Der Canvas, oder besser der 2D-Kontext des Canvas, ist dann bereit, weitere Zeichenfunktionen aufzunehmen. Die closePath()-Methode verbindet den Anfangspunkt des Pfads mit dem aktuellen End-
2.3 Das canvas-Element
97
punkt durch eine gerade Linie. Der Aufruf ist optional, da der Pfad bereits durch die angewendeten Zeichenmethoden geschlossen sein kann. Zuletzt werden die Methoden stroke() und fill() aufgerufen. stroke() zeichnet dabei den Umriss der gezeichneten Form, während fill() die Form ausfüllt. Eine sehr nützliche Methode ist moveTo(). Vereinfacht ausgedrückt, können damit Pfade gezeichnet werden, die Lücken haben. Betrachten Sie die beiden Linien des folgenden Beispiels, die mit einem einzigen Pfad gezeichnet wurden: //2 Linien, 5px Abstand ctx.beginPath(); ctx.strokeStyle "rgb(0,0,255)"; ctx.moveTo(10, 10); ctx.lineTo(260, 10); ctx.moveTo(10, 15); ctx.lineTo(260, 15); ctx.stroke();
Zunächst wird beginPath() aufgerufen, um einen neuen Pfad zu zeichnen. Da der Ursprung der ersten Linie der Punkt (10,10) sein soll, wird moveTo(10,10) aufgerufen. Die Methode lineTo() zeichnet dann die erste Linie bis zum Punkt (260, 10). Ein weiteres Mal wird moveTo() aufgerufen, um den Ursprung der zweiten Linie 5 Pixel unterhalb des ersten Ursprungs zu positionieren. Die zweite Linie wird gezeichnet, und letztlich wird mittels stroke() gezeichnet. Es sind nun zwei nicht verbundene Linien entstanden. Weitere Formen, wie beispielsweise ein Dreieck, müssen ebenfalls per Pfad-API gezeichnet werden. Um ein Dreieck zu zeichnen, wird per moveTo() zunächst der Ursprung der ersten Linie angegeben. Es folgen zwei konkret per lineTo() gezeichnete Linien. Die dritte Kante des Dreiecks muss nicht gezeichnet werden, da fill() automatisch den Pfad schließt, also closePath() aufruft, dadurch den aktuellen Endpunkt mit dem Beginn des Pfads verbindet und so das Dreieck schließt. ctx.beginPath(); ctx.fillStyle "rgb(0,255,0)"; ctx.moveTo(10, 50); ctx.lineTo(25, 20); ctx.lineTo(40, 50); ctx.fill();
Um kreisförmige Pfade zu zeichnen, stehen die Methoden arc() und arcTo() zur Verfügung, die wie folgt deklariert werden: void arc(in float x, in float y, in float radius, in float startAngle, in float endAngle, in boolean anticlockwise); void arcTo(in float x1, in float y1, in float x2, in float y2, in float radius);
98
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Schauen wir uns zunächst die Methode arc() an. Die ersten beiden Parameter, hier x und y, geben den Mittelpunkt an. Der dritte Parameter, radius, gibt den Kreisradius an. startAngle und endAngle bestimmen den Start- und Endwinkel des zu zeichnenden Kreises im Bogenmaß. Durch anticlockwise kann die Zeichenrichtung umgedreht werden. Da wir im Umgang mit Kreisen meistens in Grad denken, erstellen wir zunächst eine Funktion, die uns die Gradzahl ins Bogenmaß umrechnet: function getRadians(deg) { return (Math.PI/180)*deg; }
Durch diese kleine Hilfsfunktion können wir dann recht einfach einen Kreis zeichnen. Das folgende Beispiel zeichnet vier kreisförmige Formen. Nur die erste stellt einen vollständigen Kreis dar. Wir ziehen pro Durchgang der Schleife 90 Grad ab und erhalten auf diese Weise unterschiedliche Formen: for (var i 0; i < 4; i++) { ctx.beginPath(); var x 30 + (60*i); ctx.arc(x, 125, 20, getRadians(0), getRadians(360 (90*i)), false); ctx.fill(); } for (var i 0; i < 4; i++) { ctx.beginPath(); var x 30 + (60*i); ctx.arc(x, 170, 20, getRadians(0), getRadians(360 (90*i)), false); ctx.stroke(); }
Das folgende Bild zeigt das Resultat sowohl für den Aufruf von stroke(), um den Umriss der Form zu zeichnen, als auch für den Aufruf von fill(), um die gezeichnete Form gefüllt darzustellen: Um einen Dreiviertelkreis zu zeichnen, reicht also die arc()Methode allein nicht aus. Das Problem ist, dass der Start- und Endpunkt des gezeichneten Pfads durch eine gerade Linie verbunden wird. Um den Dreiviertelkreis zu zeichnen, bedarf es zwei weiterer Linien: ctx.beginPath(); ctx.arc(30, 215, 20, getRadians(0), getRadians(270), false); ctx.lineTo(30, 215);
2.3 Das canvas-Element
99
ctx.lineTo(50, 215); ctx.stroke(); ctx.beginPath(); ctx.arc(90, 215, 20, getRadians(0), getRadians(270), false); ctx.lineTo(90, 215); ctx.lineTo(110, 215); ctx.fill();
Das Ergebnis kann sich sehen lassen: Die Methode arcTo() zeichnet einen kreisförmigen Abschnitt. Schauen wir uns die Deklaration der Methode zunächst nochmals an: void arcTo(in float x1, in float y1, in float x2, in float y2, in float radius);
Zum Punkt (x1,y1) zeichnet arcTo() zunächst eine gerade Linie, ausgehend vom aktuellen Ursprung. (x2,y2) gibt nun den Endpunkt des kreisförmigen Pfadabschnitts an und radius den zu benutzenden Radius (vom Mittelpunkt, also x1,y1). Ein Beispiel veranschaulicht das: ctx.beginPath(); ctx.moveTo(100, 100); ctx.lineTo(160, 100); ctx.arcTo(180, 100, 180, 120, 20); ctx.lineTo(180, 180); ctx.arcTo(180, 200, 120, 200, 20); ctx.lineTo(120, 200); ctx.arcTo(80, 200, 80, 180, 20); ctx.lineTo(80, 120); ctx.arcTo(80, 100, 100, 100, 20); ctx.fill();
Die Benutzung der arcTo()-Methode braucht sicherlich etwas Übung. Sie sollten nicht vergessen, dass die ersten beiden Parameter einen Punkt angeben, zu dem zunächst eine gerade Linie gezeichnet wird und der später als Mittelpunkt des Kreises fungiert. Die nächsten beiden Parameter geben den Endpunkt an, also den Punkt, zu dem ein Kreisabschnitt gezeichnet werden soll. Der letzte Parameter gibt den Radius des Kreises an. Die Methoden quadraticCurveTo() und bezierCurveTo() werden meist für organische Formen verwendet. Sie sind wie folgt deklariert: void quadraticCurveTo(in float cpx, in float cpy, in float x, in float y); void bezierCurveTo(in float cp1x, in float cp1y, in float cp2x, in float cp2y, in float x, in float y);
Der wichtigste Unterschied ist, dass quadraticCurveTo lediglich einen Kontrollpunkt benötigt, da die Funktion quadratisch und damit symmetrisch ist. bezierCurveTo() braucht zwei Kontrollpunkte und ist daher flexibler. Folgende Darstellung zeigt je ein Beispiel.
100
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Bild 2.5: Links quadraticCurveTo und rechts bezierCurveTo.
Bei beiden Methoden ist zu beachten, dass außer den Kontrollpunkten lediglich der Endpunkt angegeben wird. Der Startpunkt ist der Endpunkt der letzten Zeichenoperation oder der Punkt, der mittels moveTo() angegeben wurde. Betrachten wir nun die quadraticCurveTo()-Methode: for (var i 0; i <script language "javascript" src "js/jquery.flot.js" type "text/javascript" > <script language "javascript"> function init() { var now new Date().getTime(); var oneDay 1000*60*60*24;
2010):
//UTC offset at the time of writing (based in Sunnyvale, CA, April 7 hrs. //this should be normalized on the server side now 1000*60*60*7;
var data [ { label: "Espresso / Day", data: [[now, 3], [now+oneDay, 7], [now+(oneDay*2), 2], [now+(oneDay*3), 3] ] } ]; var options { series: { lines: { show: true, fill: true }, points: { show:true } }, colors: ["rgba(255,0,0,0.5)"], xaxis: { mode: "time", minTickSize: [1, "day"] } }; $.plot($("#chart"), data, options ); } document.addEventListener("DOMContentLoaded", init, false);
120
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Canvas Charting
Zuerst warten Sie mittels DOMContentLoaded-Event, bis sämtliche Elemente der HTML-Seite ansprechbar sind, und starten dann die Funktion init(). Der grundlegende Aufruf von Flot geschieht in einer einzelnen Zeile. $.plot($("#chart"), data, options );
Per jQuery wird zunächst das im der HTML-Seite befindliche div-Element (mit der ID chart) referenziert und zusammen mit einem data- und einem optionsObjekt an die Methode plot() des Flot-Plug-ins übergeben. Der Code über diesem Aufruf erstellt lediglich die Beispieldaten und Optionen. Unsere Beispieldaten bestehen aus einer zeitbasierten Datenserie. Wir erstellen beispielhaft eine Datenserie für den Espresso-Konsum pro Tag. Das Array data enthält die Datenserien in Form von JavaScript-Objekten. Laut Flot-Konvention kann das Label (für die Legende) mit dem Attribut label angegeben werden. Die Daten der Serie werden im Attribut data als Array von Arrays angeführt. Pro Element werden die xund y-Koordinaten des späteren Diagramms angegeben. Da wir ein zeitbasiertes Diagramm wünschen, müssen die Daten in Form von Timestamps angegeben werden. var data [ { label: "Espresso / Day", data: [ [now, 3], [now+oneDay, 7], [now+(oneDay*2), 2], [now+(oneDay*3), 3] ] } ];
Die Optionen werden ebenfalls als JavaScript-Objekte definiert und als Parameter der Plot-Methode übergeben. Auf Details soll hier nicht eingegangen werden, die Bedeutung der einzelnen Optionen ist doch recht selbsterklärend. Die vollständige Beschreibung der Flot-API finden Sie unter http://bit.ly/bEXQYn. var options { series: { lines: {
2.3 Das canvas-Element
121
show: true, fill: true }, points: { show:true } }, colors: ["rgba(255,0,0,0.5)"], xaxis: { mode: "time", minTickSize: [1, "day"] } };
Die Beispielseite bietet einen Überblick über alle hier im Kapitel kennengelernten Canvas-Funktionen. Die gepunkteten Linien definieren den Canvas-Bereich, in den mithilfe der verschiedenen Funktionen gezeichnet wird. Die Auswahl geschieht über ein Drop-down-Menü, das wie gewohnt unter iOS 4 als scrollbare Liste angezeigt wird. Download http://www.buch.cd Hier finden Sie ein umfassendes Beispiel, in dem alle hier gezeigten canvas-Funktionen in einer mobilen Web-App gezeigt werden.
Bild 2.24: Die gepunkteten Linien definieren den CanvasBereich. Die Auswahl erfolgt über ein Drop-down-Menü.
Das Beispiel lässt sich besonders gut zum Testen auf verschiedenen Systemen und mobilen Browsern einsetzen. Während diese Funktion auf vielen Handsets und Plattformen funktioniert, sind die Composite-Operationen nicht überall so umfassend wie unter iOS 4 implementiert, obwohl auch hier einige Optionen noch nicht vollständig unterstützt werden.
122
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Bild 2.25: Nicht überall sind die Composite-Operationen so umfassend implementiert wie unter iOS 4.
2.4
Audio und Video
Erinnern Sie sich an die Zeiten, als es noch kein YouTube gab? Wann immer man im Internet ein Video sehen wollte, klickte man auf einen Link, und ein externes Programm, beispielsweise der Windows Media Player, wurde geöffnet, um das Video oder auch die Audiodatei wiederzugeben. Flash hieß Anfang dieses Jahrtausends das Zauberwort und hat die Internetvideolandschaft grundlegend verändert. Mit HTML5 steht die nächste Videorevolution bereit, die bereits damit begonnen hat, die Abhängigkeit von Flash zu beseitigen und dem Browser das Abspielen von Videos ganz zu überlassen. Auch wenn wir uns in diesem Buch meistens mit HTML5-Techniken beschäftigen, die mobilspezifisch, also für das mobile Internet und einen kleinen Bildschirm relevant sind, so ist es hier sinnvoll, auch über das iPad zu sprechen. Ein iPad-Benutzer wird auf seinem Tablet-Computer keine mobile Webseite erwarten, allerdings unterstützt das iPad kein Flash und kann somit »normale« Flash-Videos nicht wiedergeben. Der Medienrummel um das iPad und die fehlende Flash-Unterstützung hat Anfang 2010 viele der großen Webseiten dazu veranlasst, HTML5 für Video zu implementieren. HTML5 wird derzeit nur dann verwendet, wenn der Benutzer die Webseite auch mit einem kompatiblen Gerät aufruft – aber man geht davon aus, dass ohne iPad die Verwendung von HTML5-Video noch nicht so weit wäre. Reihenweise purzelten im März 2010 – einen Monat vor dem iPad-Start in den USA – die Pressemitteilungen ins Haus, dass YouTube, Flickr, Vimeo, die New York Times und viele andere auf die neue HTML5-Technologie umgestellt hätten. Flash-Video wird sicher nicht von heute auf morgen verschwinden, und mit der Android-Version 2.2 (Froyo) hat auch Flash auf mobilen Geräten wieder Einzug gehalten. Auch Microsofts mobiles Betriebssystem Windows Phone 7 soll laut Unternehmensangaben Flash unterstützen. Aber irgendwie passt es für kleine Bildschirme und mobile Geräte nicht: Wer auf den Android-Geräten die Wiedergabe von Flash-Videoinhalten ausprobiert hat, wird schnell feststellen, dass eine HTML5-Einbindung nicht nur stabiler, sondern einfach auch benutzerfreundlicher ist.
2.4 Audio und Video
123
Der große Vorteil von Flash gegenüber HTML5 ist heutzutage noch, dass die verschiedenen Browser sich nicht auf ein einheitliches Video- und Audioformat einigen konnten. Flash ist im Prinzip ein Format: Flash. Das gibt es höchstens in verschiedenen Versionen, aber es ist ein relativ einheitliches Format. Im Gegensatz dazu versteht der Safari-Browser beispielsweise nur Videoformate, die im Opera-Browser nicht funktionieren. Anbieter müssen also ihre Audio- und Videoinhalte, sofern sie sie mittels HTML5 anbieten möchten, in verschiedenen Formaten bereithalten.
2.4.1
Audiowiedergabe
Da das video-Tag komplexer als das Tag zur Audiowiedergabe ist, fangen wir erst einmal mit der Tonwiedergabe audio an. Eigentlich ist die audio-Syntax ganz einfach: Ogg Vorbis Audio wird leider nicht unterstützt. Direkter Link zur Datei: beispiel.oga.
Im audio-Element wird auf eine Datei verwiesen, die dann im Browser oder dem Standard-Medienplayer des Telefons wiedergegeben wird. Auf die Audiodatei wird mittels des src-Attributs verwiesen. Innerhalb des audio-Tags können Sie weiteres HTML einfügen, das aber nur dann angezeigt wird, falls ein Browser (beispielsweise der Internet Explorer auf einem Windows Mobile-Gerät) kein HTML5-audio-Tag versteht. Eine Audiodatei wird entweder direkt im mobilen Browser auf der Webseite oder im Standard-Medienplayer wiedergegeben, der auch zum Betrachten von Videos benutzt wird. Seit iOS 4 wird die Audiodatei direkt im Browserfenster abgespielt. Ein kleines Steuerelement wird dazu auf der Seite angezeigt. Bei älteren iPhone OS-Versionen wurde nach dem Antippen eines Buttons der Videoplayer gestartet und die Audiodatei abgespielt. Das control-Attribut, das die Einblendung der Standardsteuerelemente festlegt, wird auf einem iPhone oder einem iPod ignoriert, bei einem iPad beispielsweise aber beachtet. Wie schon oben in der Einleitung angekündigt, gibt es leider keinen Standard, dessen Dateiformat von allen Browsern unterstützt wird. Hier ist eine Übersicht: Browser
Unterstützte Audioformate
iOS Safari (iPhone, iPod touch und iPad)
AAC (M4A)
MP3
Android
AAC (M4A)
MP3
MP4
Safari 4+
AAC (M4A)
MP3
MP4
WAV (unkomprimiert) OGG Vorbis WAV
124
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Browser
Unterstützte Audioformate
Chrome 3+
MP3
MP4
OGG Vorbis
Firefox 3.5+
WAV
OGG Vorbis
Opera 10.5+
WAV
OGG Vorbis
Internet Explorer 9
AAC (M4A)
MP3
Sie müssen also, und das gilt auch für das später vorgestellte video-Element, mehrere Formate anbieten, um wirklich sicherzustellen, dass der Audioinhalt auch auf allen Geräten und Browsern wiedergegeben werden kann. Dazu ist das source-Attribut genau richtig. Mittels dieses Attributs können Sie mehrere Formate innerhalb eines audio- oder video-Tags anbieten. Dabei ist es natürlich erforderlich, dass Sie Ihre Audio- oder Videoquelle auch auf Ihrem Server in verschiedenen Formaten anbieten. Im HTML-Markup sieht das wie folgt aus: Einfacher Audio Player <source src "audio/musik.oga"> <source src "audio/musik.mp3">
Wenn Sie diesen HTML-Code auf Ihren Server laden, sieht das Ergebnis unter iOS 4 so aus:
Bild 2.26: So wird das audio-Element auf einem iPhone angezeigt.
Über das kleine Playsymbol wird die Audiowiedergabe gestartet. Sollten Sie diesen kurzen Beispielcode zusammen mit einer AAC- oder MP3-Datei auf Ihren Server laden,
2.4 Audio und Video
125
kann es passieren, dass Sie in einigen Browsern dennoch nichts hören, obwohl Sie augenscheinlich alles richtig gemacht haben. Audio- und Videodateien müssen vom Server mit dem richtigen MIME-Type ausgeliefert werden. Der – und nur der – MIME-Type übermittelt dem Browser die Information darüber, welche Art von Daten geliefert werden. Falls Sie sich bereits mit der Konfiguration auskennen, können Sie den folgenden Abschnitt überspringen, falls nicht, empfehlen wir Ihnen diese Lektüre unbedingt.
2.4.2
MIME-Types
Wann immer ein Browser eine Webseite anfragt, erhält er noch weit vor den eigentlichen HTML-Daten einige Metainformationen zur Seite, die sogenannten Header. Die Informationen in diesen Headern sind in der Regel nicht sichtbar, helfen aber dem Browser, wichtige Entscheidungen zu treffen, beispielsweise wie später der empfangene Inhalt darzustellen ist. Der Header, der dem Browser übermittelt, ob es sich bei den empfangenen Daten um eine Textdatei (also eine HTML-Datei), um Video-, Bild- oder Audiodaten handelt, nennt sich Content-Type-Header und besitzt meist folgende Werte: Content-Type
Inhalt
text/html
Normale HTML-Webseite und Textdokumente.
image/jpeg
Bilder im JPEG-Format.
image/png
Bilder und Grafiken im PNG-Format.
audio/ogg
Audiodateien im OGG Vorbis-Format.
video/mp4
Videodateien im MP4-Format.
Die Konfiguration der MIME-Types ist je nach verwendetem Webserversystem unterschiedlich. Sind Sie sich nicht sicher, wie die MIME-Types auf Ihrem Server gesetzt werden, hilft es meistens schon, die Audio- und Videodateien in separate Verzeichnisse zu speichern und diese Verzeichnisse mit einer sogenannten .htaccess-Datei zu versehen. Die .htaccess-Datei ist eine Datei ohne Endung und wird in einem Verzeichnis mit den Mediendaten gespeichert. Schreiben Sie den folgenden Inhalt in die .htaccess-Datei, um die unterstützten Medienformate festzulegen und den Webserver zu veranlassen, bei Anfrage den richtigen Content-Header zu schicken: AddType AddType AddType AddType AddType
audio/mpeg .mp3 audio/ogg .oga video/ogg .ogv video/mp4 .mp4 video/webm .webm
Mit diesen fünf Zeilen sagen Sie dem Webserver, dass er, beispielsweise wenn eine OGG Vorbis-Datei mit der Endung .oga angefragt wird, den Content-Type audio/ogg mit zu versenden hat. Anhand dieser Information kann dann der Browser gleich sehen, ob er die Musikdatei unterstützt, und muss sie nicht erst selbst herunterladen, um das festzustellen.
126
Kapitel 2 – HTML5 in der mobilen Webentwicklung
2.4.3
Aufbau einer Videodatei
Wie schon bei den unterstützten Audioformaten gibt es auch bei den in den jeweiligen Browsern unterstützten Videoformaten keine Übereinstimmung. Man hatte sogar versucht, sich darauf zu einigen, dass mindestens das offene Videoformat OGG Theora unterstützt wird – leider ohne Erfolg. Um Video bestmöglich und effektiv in HTML5 und speziell auf mobilen Geräten einsetzen zu können, müssen wir uns erst einmal mit dem Aufbau einer Videodatei beschäftigen. Wie schon bei einer Audiodatei wird in HTML5 einfach über ein simples Tag auf die Videodatei verwiesen:
Die Datei film.ogv ist aber, wie jede Videodatei, keine einzelne Videodatei, sondern eine Art ZIP-Archiv, das weitere Dateien enthält. Man nennt diese Dateien Videocontainer, da sie wie eine große Box eine Vielzahl von weiteren Daten in unterschiedlichen Formaten enthalten können. Videocontainerformate In der Regel befinden sich in einem Videocontainer neben der Sammlung von Metadaten zum Video (Titel, Herstellername) mehrere Spuren (Tracks): eine Bildspur und mindestens eine Tonspur. Tonspuren bestehen meistens aus einem der im audioAbschnitt vorgestellten Formate. Für HTML5 sind die folgenden Videocontainerformate interessant: Format
Dateiendung
Beschreibung
OGG
.ogv
Offenes und ziemlich verbreitetes Videoformat, das mit dem OGG Vorbis-Audioformat verwandt ist. Das Videocontainerformat wird auch »OGG Theora« genannt. OGG Theora wird von einer Vielzahl von Browsern unterstützt, beispielsweise auch von Android.
MPEG-4
.mp4 oder .m4v
Ein sehr bekanntes und vor allem von Apple verwendetes Medienformat. MPEG-4-Container können neben den Videound Audiospuren auch weitere Informationen, wie beispielsweise Untertitel oder Standbilder, enthalten. Die enge Verbindung zu Apple kommt nicht von ungefähr: Das Format basiert auf dem alten QuickTime-Containerformat der Firma. MPEG-4 kann im Gegensatz zu OGG Theora auf den AppleGeräten verwendet werden.
AVI
.avi
Dieses Containerformat dürfte vor allen Dingen WindowsBenutzern etwas sagen. Schließlich wurde es bereits 1992 von Microsoft als Teil der »Videos für Windows«-Technologie vorgestellt. Obwohl das Videocontainerformat alt ist und wenig weiterentwickelt wurde, findet es immer noch eine große Verbreitung und wird auch von diversen HTML5-kompatiblen Browsern unterstützt.
2.4 Audio und Video
127
Format
Dateiendung
Beschreibung
WebM
.webm
Nachdem wir schon Dateiformate von Microsoft und Apple kennengelernt haben, darf natürlich eine Firma nicht fehlen: Google. Das WebM-Format wurde erst 2010 auf Googles Entwicklerkonferenz vorgestellt und soll insbesondere für HTML5 ein lizenzfreies und hoch qualitatives Videoformat anbieten. Ein WebM-Container enthält in der Regel eine Videospur im VP8-Videoformat und OGG Vorbis-Audiospuren. Als erster mobiler Browser wird Android das neue offene Videoformat ab Ende 2010 unterstützen.
2.4.4
Videocodecs
Sicher waren Sie auch schon einmal in der Situation, dass Sie eine Videodatei – oder wie wir jetzt wissen, eine Videocontainerdatei – hatten, die einfach kein Bild, sondern nur Ton lieferte. QuickTime auf dem Mac zeigt dann den wohlbekannten Dialog: Zusätzliche Software ist zur Wiedergabe erforderlich. Was dem Videoabspielprogramm in solchen Momenten fehlt, ist der richtige Videocodec. Ein Videocodec ist ein Algorithmus, der dem Abspielprogramm sagt, wie die Videodaten im Videocontainer decodiert und dargestellt werden sollen. Würden Sie im Internet die Bilder wie in einem klassischen Film darstellen – also lauter abgespeicherte Einzelbilder, die mit 25 Bildern pro Sekunde angezeigt werden –, hätten Sie es mit riesigen Dateien und, gerade auf Mobiltelefonen, wahrscheinlich mit stundenlangen Ladezeiten zu tun. Moderne Videocodecs codieren Bildabfolgen viel intelligenter. Anstatt jedes Bild einzeln abzuspeichern, werden nur die Unterschiede zwischen den Bildern über einen bestimmten Algorithmus beim Codieren gesichert. Damit das Abspielprogramm diesen Algorithmus versteht, muss es den Codec wissen, mit dem die Videodaten codiert wurden. Ein Video besteht daher immer aus mindestens drei Teilen: 1. der in einem bestimmten Codec codierten Videodatei, 2. einer Audiodatei sowie 3. dem entsprechenden Videocodec. Folgende Videocodecs sind für HTML5 relevant: Für HTML5 relevante Videocodecs Theora
Theora ist wie auch das OGG-Containerformat lizenzfrei. Während die Unterstützung von Theora auf Desktop-Browsern relativ weit verbreitet ist (Firefox, Chrome, Opera), wird der Codec derzeit nicht von iOS und bislang auch noch nicht von Android unterstützt. Ein weiterer Nachteil des Codecs ist, dass er seit geraumer Zeit kaum noch aktiv weiterentwickelt wird.
128
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Für HTML5 relevante Videocodecs VP8
Die Chancen stehen gut, dass sich VP8 als aktiv weiterentwickelter Nachfolger von Theora etabliert. Der Codec wurde von der gleichen Firma entwickelt, die auch den Theora-Vorgänger programmierte, und wurde schließlich 2010 von Google gekauft. Google hat die auf dem Codec beruhenden Patente freigegeben, und heutzutage ist VP8 als lizenzfreier Codec erhältlich und wird im Zuge des WebM-Containerformats von immer mehr Browserherstellern unterstützt. Im mobilen Bereich wird der Codec, da auch kräftig durch Google gefördert, als Erstes von Android wahrscheinlich Ende des Jahres 2010 unterstützt werden.
H.264
Die meisten großen Videowebnamen unterstützen heutzutage den H.264Codec: YouTube, Flickr, Vimeo – und einer der Gründe, warum das so ist, nennt sich iPhone. Apple unterstützt auf all seinen mobilen Geräten (iPhone, iPod touch, iPad) den Codec, und auch sämtliche Android-Telefone verstehen den Algorithmus. H.264 wurde von der MPEG-Gruppe entwickelt und ist daher auch als MPEG-4 bekannt. H.264 ist prädestiniert für die Benutzung auf mobilen Geräten, da der Codec darauf zielt, einen einzigen Codec für Geräte mit geringer Rechenleistung und langsamen Datenverbindungen anzubieten (beispielsweise Mobiltelefone), gleichzeitig aber auch für Computer, die hoch qualitative Videos mit hoher Rechenleistung und hoher Datenbandbreite abspielen. Um diesen Spagat zu bewältigen, verwendet H.264 verschiedene Profile, mit denen festgelegt wird, welche Funktionen auf welchen Geräten zur Verfügung gestellt werden. Hoch qualitative Blu-ray-Videos werden mit einem High-Profile encodiert, bieten daher auch eine sehr gute Bildqualität, benötigen aber auch recht viel Rechenpower, um die Daten zu decodieren. Diese Rechenpower hat ein Mobiltelefon bislang noch nicht, deshalb unterstützt Apple für das iPhone und den iPod touch nur ein niedrigeres Profil, das sogenannte »Baseline-Profil«. Obwohl sich mit H.264 Videos zuverlässig auf mobilen Geräten und vielen Desktop-Webbrowsern wiedergeben lassen, ist der Codec nicht lizenzfrei. Anbieter von En- und Decodern für den H.264-Codec müssen ab 1. Januar 2011 Lizenzgebühren an den Lizenzverwalter MPEG LA zahlen. Eine Ausnahmeregelung, die kostenfreies Webvideo von Lizenzzahlungen ausnimmt, gilt noch bis 31. Dezember 2016. Bitte beachten Sie, dass diese Ausnahmeregelung nur für im Internet angebotenes H.264-Video gilt, das der Benutzer kostenfrei ansehen kann. Andere Webvertriebsformen, beispielsweise kostenpflichtige Abodienste, sind möglicherweise lizenzpflichtig. Nähere Informationen finden Sie direkt beim Lizenzverwalter: www.mpegla.com (»Request a License«).
Nach so vielen Informationen zu den verschiedenen Codecs ist es sicherlich hilfreich, alles einmal in eine Tabellenform zu bringen, um zu sehen, welcher Browser welches Videocontainerformat und welchen Codec unterstützt.
2.4 Audio und Video
Browser
Unterstützte Videocontainerformate und -codecs
iOS Safari (iPhone, iPod touch und iPad)
MPEG-4 und QuickTime mit H.264 (Baseline-Profil-encoded)
Android
MPEG-4 mit H.264 (Baseline-Profil-encoded)
BlackBerry OS 6
MPEG-4 mit H.264 (Baseline-Profil-encoded)
Safari 3+
MPEG-4 mit H.264
Chrome
MPEG-4 mit H.264
129
ab Ende 2010: WebM mit VP8 Codec
ab Chrome 6: WebM mit OGG Theora VP8 Codec
Firefox
ab Firefox 4: WebM mit VP8 Codec
OGG Theora
Opera
ab Opera 11: WebM mit OGG Theora VP8 Codec
Internet Explorer 9
WebM mit VP8 Codec; Codec muss zusätzlich installiert sein
Mit der Vielzahl von unterschiedlichen Videocontainerformaten und -codecs ist es auch wie beim audio-Tag erforderlich, dass Sie mehrere Formate zur Verfügung stellen. Eine Anleitung, mit welchen Tools Sie Video- und Audiodateien am besten in die gewünschten Formate konvertieren, finden Sie weiter unten in diesem Kapitel. Unterschiedliche Quellen können Sie wie beim Einbinden von Audiodateien auch über den source-Parameter steuern: <source src "film.mp4" type ’"video/mp4; codecs "mp4a.40.2"'/> <source scr "film.ogv" type '"video/ogg; codecs "theora, vorbis"' /> HTML5 Video kann nicht abgespielt werden. Besorg dir einen neuen Browser!
Wie auch beim audio-Tag versucht der Browser jetzt, die angebotenen Formate von oben nach unten durchzugehen, um zu sehen, welches Videocontainerformat und welcher Codec wiedergegeben werden kann. Es empfiehlt sich, MPEG-4-/H.264-Videos als erste Option anzubieten, da diese Kombination von den meisten (mobilen) Browsern unterstützt wird und beispielsweise das iPad nur den ersten source-Eintrag liest. Ein Fehler, der hoffentlich bald behoben wird.
130
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Mittels des im Beispielcode verwendeten type-Attributs können Sie dem Browser gleich von Anfang an die Information geben, welches Containerformat und welcher Codec für das Video gewählt wurde und vom Browser gewählt werden soll. Das hat den großen Vorteil, dass der Browser nicht erst das Video laden muss, um das Format zu erkennen, sondern gleich im HTML-Code sehen kann, ob er das Videocontainerformat und den Codec unterstützt oder nicht. Das video-Tag kann mit einer Reihe von Attributen kommen, die wir jetzt im Detail vorstellen möchten. autoplay Das autoplay-Attribut haben wir bereits beim audio-Tag kennengelernt. Wie schon dort würde dieses Tag veranlassen, dass das Video gleich nach dem Laden der Seite automatisch gestartet wird. Da mobile Benutzer möglicherweise viel Geld für die Datenübertragung – gerade bei datenintensiven Inhalten wie Videos – bezahlen müssten, funktioniert die autoplay-Option nicht auf dem iPhone und auch nicht auf dem iPad. Auf einem nicht mobilen Gerät braucht der Benutzer jedoch keinen Play-Button anzutippen. Die autoplay-Option wird wie folgt eingebunden:
oder so:
Da das autoplay-Attribut nur ein Boole'scher Ausdruck ist, reicht die Angabe von autoplay auch ohne Parameter. controls Falls verwendet, werden im Browser die Standardsteuerelemente zur Videowiedergabe mit angezeigt. Man könnte mit JavaScript eigene Steuerelemente bauen, allerdings ist das für die mobile Verwendung wenig sinnvoll. Die Bildschirme sind ohnehin klein, und der Nutzer hat sich bereits an die Steuerelemente beispielsweise auf einem iPhone gewöhnt. Aus diesem Grund wird das Attribut auch auf einem iPhone oder einem iPod touch ignoriert, auf einem iPad allerdings berücksichtigt. Die Standardelemente beinhalten: •
Play/Abspielen
•
Pause
•
Volume
•
Vor- und Zurückspulen
Manche Browser, insbesondere Desktop-Browser, bieten noch zusätzliche ControlElemente. Auch das Aussehen der Standardelemente können Sie ohne die Verwendung von JavaScript nicht beeinflussen. Wie schon das autoplay-Attribut kann auch controls ohne Parameter in das video- oder audio-Tag mit eingebunden werden:
2.4 Audio und Video
131
loop Falls vorhanden, wird der Audio- oder Videoinhalt nach dem Abspielen automatisch wiederholt.
poster="url" (nur für Video-Tag) Falls vorhanden, gibt die im Attribut angegebene URL den Pfad zu einem Bild an, das das Video repräsentieren soll. Es handelt sich dabei um etwas Ähnliches wie das StartupBild beim iPhone, das nach dem Antippen des Icons so lange dargestellt wird, bis die Anwendung geladen ist. Bei einem Video kann es zum Beispiel der erste Videoframe sein, der angezeigt wird, bis das Video geladen ist. Das Posterbild wird also so lange angezeigt, bis der erste Frame des Videos verfügbar ist. Danach wird es gegen den ersten Videoframe ausgetauscht. Auf einem iPhone oder einem iPod touch wird seit iOS 4 der erste Videoframe ebenfalls bereits im Browser angezeigt, obwohl das Video im Standardmedienprogramm wiedergegeben wird. Das folgende einfache Codebeispiel verwendet kein poster-Attribut und wird auf einem iPhone oder iPod mit einem Standardabspielelement dargestellt. Einfacher Videoplayer
Auf einem iPod oder iPhone sieht der Ablauf dann wie folgt aus. Ein Standardelement wird nach dem Laden der Seite angezeigt. Der Benutzer kann jetzt schon den Playbutton antippen.
Bild 2.27: Anzeige eines Standardelements.
132
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Nach wenigen Sekunden wird der erste Videoframe geladen und angezeigt. Das Antippen des Play-Buttons ruft den Standardmedienplayer auf.
Bild 2.28: Anzeige des ersten Videoframes.
Im Standardplayer wird das Video wiedergegeben. Als Programmierer muss man sich nicht um die Steuerelemente kümmern, da sie vom System angeboten werden.
Bild 2.29: Wiedergabe des Videos im Standardplayer.
Wird der erste Videoframe als Bild abgespeichert und im poster-Attribut verwendet, ändern sich Code und Darstellung wie folgt: Einfacher Videoplayer
Gleich nach dem Laden der Seite wird das Posterbild anstelle der schwarzen Box angezeigt. Für den Benutzer sieht es so aus, als sei das Video gleich verfügbar und müsste nicht erst noch geladen werden. Nach dem Antippen wird wieder der Standardplayer aufgerufen. In der Zeit zwischen dem Laden des Posterbilds auf der Webseite und dem Aufrufen des Players sollte schon so viel Zeit vergangen sein, dass hier auf jeden Fall bereits der erste Frame angezeigt werden kann.
Bild 2.30: Anzeige des Posterbilds. Beim Antippen wird der Standardplayer geladen.
•
width=" – Anzahl der Bildpunkte oder Prozentwert"
•
height=" – Anzahl der Bildpunkte oder Prozentwert" (nur für video-Tag)
Mit diesen Werten kann die Wiedergabegröße des Videos bestimmt werden, zumindest wenn das Video nicht auf einem kleinen Bildschirm wiedergegeben wird. Wir erinnern uns: Bei vielen mobilen Geräten werden Videos nicht im Browser, sondern im Standardmedienplayer wiedergegeben. Werden die width- und height-Attribute nicht verwendet, wird, wie in den Abbildungen oben dargestellt, eine schwarze Box von mindestens 300 x 150 Bildpunkten auf iPhones oder iPod touch-Geräten angezeigt. Wichtig ist auch zu bemerken, dass die Angabe der Breite (width) und Höhe (height) im video-Tag nicht das Verhältnis ändert, mit dem das Video aufgezeichnet oder konvertiert wurde. Sie können nicht aus einem 4:3-Video mittels dieses Attributs ein schickes 16:9-Video zaubern. Einfacher Videoplayer
134
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Hier sehen Sie ein eingebundenes Video auf einem iPod ohne width- und heightParameter und daneben ein eingebundenes Video auf einem iPod mit width- und height-Parametern. Das Videos wird weiterhin im Standardmedienplayer wiedergegeben.
Bild 2.31: Video auf einem iPod ohne und mit widthund height-Parameter.
Und dies ist ein eingebundenes Video auf dem iPad, ebenfalls mit width und height. Im Gegensatz zu iPhone und iPod findet die Videowiedergabe direkt auf der Webseite und in den angegebenen width- und height-Abmessungen statt.
Bild 2.32: Eingebundenes Video auf dem iPad.
2.4 Audio und Video
135
Falls Sie Videos mittels HTML5 in viele Bereiche Ihrer Webpräsenz einbauen wollen und alle über eine konstante Breite und Höhe verfügen sollen, empfiehlt es sich, das video-Tag gleich mit CSS am Anfang des Codes zu bearbeiten und die Standardhöhen dem Tag generell zuzuweisen: video { width: 320px; height: 240px; }
preload="none", preload="metadata", preload="auto" Mit dem preload-Attribut kann bestimmt werden, dass ein Video teilweise oder vollständig geladen wird, bevor der Benutzer die Wiedergabe starten kann. Sie können dem Desktop-Browser mit diesem Attribut also mitteilen, ab wann Ihrer Meinung nach die Wiedergabe eines Videos (oder einer Audiodatei) sinnvoll gestartet werden kann. Manche Browser ignorieren das preload-Attribut, wenn beispielsweise genug Bandbreite zum einwandfreien Laden und gleichzeitigem Wiedergeben des Videos vorhanden ist. Auch alle bislang bekannten mobilen Browser ignorieren dieses Attribut, da es eventuell ungewollten und mitunter für den Benutzer teuren Netzwerk-Traffic verursachen könnte. Folgende Werte kann das preload-Attribut haben: •
none – Ein Vorausladen der Audio- oder Videodatei ist nicht notwendig. Das sollten
Sie insbesondere dann verwenden, wenn das jeweilige Video kein Hauptbestandteil der Seite ist und die Wahrscheinlichkeit nicht sehr groß ist, dass der Benutzer das Video ansehen möchte. •
metadata – Hat die gleiche Auswirkung wie none, nur dass hier die sogenannten Metadaten des Videos, also Dauer, Dateigröße etc., geladen werden, jedoch nicht die wirklichen Audio- und Videodaten.
•
auto – Sagt dem Browser, dass entweder einige Teile oder das komplette Video
idealerweise bereits vorgeladen werden sollten. Safari kocht derzeit noch sein eigenes Süppchen und ignoriert das Attribut komplett, hört aber auf ein Attribut namens autobuffer – das ebenfalls veranlasst, dass ein Video nach Möglichkeit sofort in den Speicher geladen wird. Auch autobuffer ist in der mobilen Safari-Version wirkungslos, da ein mobiler Nutzer über entstehenden Datenverkehr immer explizit selbst entscheiden muss.
2.4.5
Fehlerbehandlung
Sie haben sicherlich schon gemerkt, dass die Wiedergabe von Videos (und in bestimmtem Umfang auch die Wiedergabe von Audiodateien) eine recht komplexe Sache mit vielen Fehlerquellen ist. Mithilfe der JavaScript-API kann man dem Benutzer zumindest einige Fehlerquellen kommunizieren. Videoplayer mit Fehler Handling <meta name "layout" content "webkit" /> <style type "text/css" media "screen">
136
Kapitel 2 – HTML5 in der mobilen Webentwicklung
<script> function fehler(e) { // Fehler bei Videowiedergabe Warum? switch (e.target.error.code) { case e.target.error.MEDIA ERR ABORTED: alert('Abbruch durch Benutzer.'); break; case e.target.error.MEDIA ERR NETWORK: alert('Durch fehlende Netzwerkverbindung konnte das Video ganz oder teilweise nicht geladen werden.'); break; case e.target.error.MEDIA ERR DECODE: alert('Video Datei ist fehlerhaft.'); break; case e.target.error.MEDIA ERR SRC NOT SUPPORTED: alert('Video Format wird nicht unterstützt.'); break; default: alert('Unbekannter Fehler ist aufgetreten.'); break; } }
Falls beispielsweise im video-Tag auf ein Video verwiesen wird, das der Browser nicht unterstützt, sieht der Benutzer die folgende Fehlermeldung auf einem iPod touch oder iPhone. In der Abbildung sehen Sie auch, dass im iOS bei einem fehlerhaften Video der Play-Button nicht richtig dargestellt wird. Mit dem gerade vorgestellten Error-Handling können Sie Ihren Benutzern schnell mitteilen, warum das Video nicht abgespielt werden kann.
Bild 2.33: iOS meldet ein fehlerhaftes Videoformat.
2.4 Audio und Video
137
Die möglichen Fehlercodes noch einmal in Tabellenform: Mögliche Fehlercodes MEDIA_ERR_ABORTED
Der Ladeprozess bzw. Prozess zum Abspielen des Videos wurde vom Benutzer abgebrochen.
MEDIA_ERR_NETWORK
Das angeforderte Video konnte teilweise oder ganz nicht geladen werden. Diese Fehlermeldung kann des Öfteren auf mobilen Geräten auftreten, wenn beispielsweise kein oder nur sehr geringer Datenempfang vorherrscht.
MEDIA_ERR_DECODE
Der Videoplayer unterstützt das Format, kann aber das Video nicht decodieren – ein Anzeichen dafür, dass die Videodatei beschädigt sein könnte oder Probleme mit dem Decoder vorliegen.
MEDIA_ERR_SRC_NOT_ SUPPORTED
Der Videoplayer kann das verwendete Videoformat nicht erkennen. Dabei kann es sich um das Videocontainerformat handeln, aber auch um den jeweiligen Codec. Sie erhalten diese Fehlermeldung auch, wenn Sie beispielsweise eine vom iPhone unterstützte MP4-Datei mit einem H.264Codec aufrufen wollen, der mit einem High-Profile codiert wurde. Wir erinnern uns: Safari für iPhone und iPod touch unterstützt, wie die meisten anderen mobilen Browser auch, nur das Baseline-Profile in H.264-Codierungen.
2.4.6
Videoimplementierung mittels JavaScript-API
Mit der JavaScript-API erhalten Sie weitaus umfangreichere Möglichkeiten, Videoinhalte mit HTML5 zu steuern und einzubauen. Das nächste Beispiel funktioniert auf den meisten Desktop-Browsern, insbesondere bei Chrome und Safari. Die nahezu volle Unterstützung der JavaScript-API für Video konnten wir bislang nur unter iOS 4 finden, deshalb funktionierte dieser Code auch zum Zeitpunkt der Entstehung dieses Buchs nur auf einem iPhone 4 oder einem anderen Apple-Gerät mit iOS 4 fehlerfrei. Das Beispiel zeigt am Anfang, ob der verwendete Browser das HTML5-video-Tag überhaupt unterstützt. Falls HTML5-Video unterstützt wird, überprüft der Code, ob die beiden Videocodecs H.264 und Theora vom Browser verstanden werden. Auf einem iPod mit OS 4.0 ergibt sich folgendes Bild:
138
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Bild 2.34: Richtig erkannt: Safari für iOS 4.0 unterstützt H.264, aber nicht Theora.
Über den Button Video buffern wird die JavaScript-Funktion movie.load() aufgerufen, die das Video in den Speicher lädt. Ohne die Seite komplett neu zu laden, wird der aktuelle Ladestatus oberhalb des Videos in Prozenten angezeigt. Die Funktion movie. play() ruft bei iPod touch und iPhone den Standardmedienplayer auf und beginnt damit, das Video abzuspielen. In einem Desktop-Browser wie beispielsweise Chrome wird das Video in der angegebenen Größe direkt im Browserfenster abgespielt. Dort ergibt dann auch die Verwendung von movie.pause() mehr Sinn, da damit das Abspielen des Films im Browserfenster unterbrochen werden kann. HTML5 Videoplayer <meta content "minimum scale 1.0, width device width, maximum scale 0.6667, user scalable no" name "viewport" /> <meta name "layout" content "webkit" /> <script src "javascript/functions.js" type "text/javascript"> <script> (function my() { var $i
{};
$i.init function() { var detectionNode, msg '', formats, pos, audio; detectionNode document.getElementById('detection'); if (!$i.hasVideo()) msg + 'Video Tag wurde NICHT erkannt
'; else { msg + 'Video Tag wurde erkannt
';
2.4 Audio und Video
139
formats { h264 : 'video/mp4; codecs "avc1.42E01E, mp4a.40.2"', theora : 'video/ogg; codecs "theora, vorbis"', }; for (pos in formats) { video document.createElement('video'); if(!!(video.canPlayType && video.canPlayType(formats[pos]).replace(/no/, ''))) msg + pos + ' wird unterstützt
'; else msg + pos + ' wird nicht unterstützt
'; } } detectionNode.innerHTML
msg;
if (!$i.hasVideo()) return; var movie
document.getElementById('movie');
document.getElementById('load').addEventListener('click', function(e) { movie.load(); }, false); document.getElementById('play').addEventListener('click', function(e) { movie.play(); }, false); document.getElementById('pause').addEventListener('click', function(e) { movie.pause(); }, false); movie.addEventListener('progress',function(e){ var soFar parseInt(((movie.buffered.end(0) / movie.duration) * 100)); document.getElementById("status").innerHTML soFar + '%'; },false); movie.addEventListener('canplaythrough',function(e){ movie.play(); },false); movie.addEventListener('loadedmetadata',function(e){ alert('size: ' + movie.videoWidth + '/' + movie.videoHeight); },false); }; $i.hasVideo
function()
140
Kapitel 2 – HTML5 in der mobilen Webentwicklung
{ return !!document.createElement('video').canPlayType; }; document.addEventListener("DOMContentLoaded", $i.init, false); }).call(); Erkennung
2.4.7
2-pass Encoding – was ist das?
Wenn Sie als Qualitätskriterium entweder die Zielgröße der Filmdatei oder die mittlere Bitrate verwenden, haben Sie auch noch die Möglichkeit, über eine kleine Checkbox das sogenannte »2-pass Encoding« zu aktivieren. In diesem Fall erhöht sich zwar die Zeit, die das quelloffene Encoding-Programm HandBrake zum Codieren des Videos benötigt, aber das Codieren wird dann in zwei Schritten durchgeführt. Im ersten Schritt wird das Video genau nach den Gesichtspunkten analysiert, die für den zweiten Schritt – das eigentliche Codieren – hilfreich sind. Auch wenn das 2-
2.4 Audio und Video
141
pass Encoding länger dauert, sichert es in der Regel eine bessere Videoqualität zu. Beachten Sie, dass bei den iPhone-Voreinstellungen automatisch die Constant QualityQualitätsoption ausgewählt wird, die kein 2-pass Encoding zulässt. •
Die Framerate in Frames pro Sekunde (FPS) brauchen Sie ebenfalls nicht zu verändern. In der Standardeinstellung wird die gleiche Framerate wie in der Originaldatei verwendet, was für den Großteil der Videocodierungen passt.
•
Die Option Web optimized ist leider standardmäßig nicht aktiviert, sollte aber für jegliche Videocodierung für die Internetwiedergabe ausgewählt sein. Ist diese Option gesetzt, werden die Videodaten so codiert, dass das Video schon mit wenigen geladenen Daten am Anfang wiedergegeben werden kann und im Hintergrund noch weitere Daten nachlädt. Die Einstellung hat keine Auswirkungen auf die Videoqualität oder den Codec, resultiert aber in einer besseren Benutzbarkeit für den Anwender.
•
Vergewissern Sie sich noch einmal, ob in der Auswahl des Videocodecs H.264 gewählt wurde. Der alternativ angebotene Codec, FFmgpeg, funktioniert auf den meisten mobilen Geräten nicht.
Werfen Sie zum Abschluss einen Blick auf die Audioeinstellungen. Sofern Sie in den Voreinstellungen Apple iPhone & iPod touch ausgewählt haben, brauchen Sie wahrscheinlich auch hier keine Änderungen mehr vorzunehmen. Beachten Sie nur, dass für die gewünschte Tonspur auch wirklich der AAC-Audiocodec ausgewählt ist.
Bild 2.35: Einstellung auf AAC-Audiocodec?
Sie haben alles überprüft? Dann klicken Sie im oberen Fensterbereich auf Start, und HandBrake wird damit beginnen, Ihr Video mit den gewünschten Einstellungen zu codieren und in das Zielverzeichnis zu speichern. Ein Statusbalken zeigt den Fortschritt im unteren Fensterbereich an.
142
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Ob die Codierung mit HandBrake wirklich erfolgreich war, können Sie am besten mit einem kleinen HTML5-Video feststellen. Hier der Sourcecode: HandBrake Test
Bild 2.36: Die HandBrake-Codierung war erfolgreich.
OGG Theora/OGG Vorbis mit Firefogg Das nächste Programm, das wir Ihnen zur Videokonvertierung vorstellen, ist Firefogg. Firefogg ist eigentlich kein richtiges Programm, sondern eine Erweiterung für den Firefox-Browser und läuft daher auf allen Betriebssystemen, auf denen auch Firefox läuft: Windows, Mac OS X und Linux. Und Sie benötigen natürlich den Firefox-Browser ab Version 3.5. Das Herzstück von Firefogg ist ein Programm namens ffmpeg2theora. Das Konvertierungsprogramm wird zwar auf der OGG Theora-Seite empfohlen, lässt sich aber nur über die Kommandozeile bedienen. Firefogg bietet zu ffmpeg2theora die grafische Benutzeroberfläche. Um Firefogg zu installieren, starten Sie einfach den Firefox-Browser und gehen zu folgender Webadresse: www.firefogg.org. Auf der Webseite sehen Sie einen roten Button, über den Sie Firefogg auf Ihrem Rechner als Firefox-Erweiterung installieren können.
2.4 Audio und Video
143
Bild 2.37: Klicken Sie auf Allow oder Erlauben, um Firefogg zu installieren.
Nach dem Anklicken von Install Firefogg erscheint im oberen Browserfenster eine gelbe Leiste mit einer Sicherheitsabfrage. Diese können Sie ruhigen Gewissens mit Allow oder Erlauben beantworten. Anschließend wird Firefogg heruntergeladen und installiert. Um die Installation abzuschließen, muss Firefox neu gestartet werden; ein entsprechendes Dialogfenster bietet das nach der Installation auch gleich an. Nach dem Neustart des Browsers und einer erfolgreichen Installation von Firefogg sehen Sie beim Aufrufen von www.firefogg.org nun ein grünes Rechteck mit der Nachricht Firefogg installed. Um ein erstes Video zu konvertieren, klicken Sie auf den Link Make Web Video.
Bild 2.38: Firefogg versteht viele Sprachen, darunter auch Deutsch.
Falls Sie Firefogg noch nicht in Deutsch sehen, können Sie es jetzt oder auch eine der vielen anderen Sprachen auswählen. Wie bei HandBrake startet auch hier der Konvertierungsprozess mit einer Quelldatei.
144
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Wir verwenden in unserem Beispiel wieder die gleiche HD-Videodatei der Flip-Kamera, die wir bereits im H.264-Beispiel in ein mobiles Format konvertiert haben. Klicken Sie dazu auf Wähle Datei und wählen Sie dann eine Videodatei von Ihrer Festplatte aus. Sobald das Video geladen ist, sehen Sie im Firefogg-Fenster viele Einstellungsmöglichkeiten. Wir gehen alle sechs Menüpunkte durch: Voreinstellungen Wie HandBrake bietet auch Firefogg eine Reihe von Voreinstellungen an. Für das Theora-Videoformat gibt es drei vordefinierte Auswahlmöglichkeiten, die sehr unterschiedliche Ergebnisse liefern. Um Videos auf mobilen Geräten anzuzeigen, dürfte die Standardoption Internetvideo (400 kBits und 400 Pixel maximale Größe) ausreichen, jedoch werden wir gleich noch sehen, wie wir Bildgröße und Videoqualität anders beeinflussen können. Das Original-HD-Video hat in unserem Beispiel eine Größe von knapp 49 MByte bei einer Laufzeit von weniger als 40 Sekunden. Die verschiedenen Theora-Voreinstellungen liefern folgende Ergebnisse: Bildbeispiel
Bezeichnung der Voreinstellungen
Dateigröße
Niedrige Bandbreite Theora, 164 KBit/s und 200 Pixel maximale Größe
940 KBit
Internetvideo Theora, 400 KBit/s und 400 Pixel maximale Größe
3 MByte
Hohe Qualität Theora, 1.080 Pixel maximale Größe
11 MByte
Codierungsbereich Über diesen Menüpunkt legen Sie fest, welcher zeitliche Bereich des Videos codiert werden soll. Das ist insbesondere dann hilfreich, wenn Sie die Qualität der Codierung bei einem längeren Video testen wollen. Gute Codierungen brauchen ihre Zeit und können bei längeren Videos leicht viele Minuten dauern. Mithilfe der Menüoption können Sie beispielsweise nur die ersten oder letzten zehn Sekunden codieren lassen, das Ergebnis evaluieren und gegebenenfalls nach etwas »Feintuning« das gesamte Video codieren. Qualitäts- und Auflösungseinstellungen Wie der Name schon sagt: Mit diesen Einstellungen legen Sie die Video- und Audioqualität, aber auch den zu verwendenden Codec fest.
2.4 Audio und Video
145
Bild 2.39: Festlegen der Qualitäts- und Auflösungseinstellungen.
Für die Video- und Audioqualität stehen Ihnen zwei selbsterklärende Schieberegler zur Verfügung. Sind sie ganz weit nach rechts geschoben, bedeutet das eine hohe Qualität, scharfe Bilder und klaren Sound, allerdings auch eine immense Dateigröße, weit nach links eingestellt, bedeuten sie das Gegenteil. Je nach Ihren Bedürfnissen müssen Sie diese Einstellungen verändern, bis Sie zufrieden sind. Unter den oberen Schiebereglern finden Sie die Auswahlmenüs für die zu verwendenden Codecs. Da wir in diesem Beispiel ein OGG Theora-Video mit OGG Vorbis-Audiocodec erstellen möchten, sollten diese beiden Codecs auch ausgewählt sein. Wie HandBrake lässt Firefogg Änderungen an der Videogröße zu. Für eine mobile Wiedergabe bietet es sich in der Regel an, eine der üblichen Bildschirmgrößen zu benutzen. HandBrake hat für eine iPod touch- und iPhone-Konvertierung eine Videobreite von 480 Bildpunkten vorgeschlagen, was wir hier anhand des Videobreite-Schiebereglers auch einstellen können. Sobald Sie einen der beiden Regler verschieben, sehen Sie, dass sich die Regler für Höhe bzw. Breite ebenfalls auf einen neuen Wert verschieben. Firefogg behält also immer die Proportionen eines Videos bei und erlaubt dort, im Gegensatz zu HandBrake, keine Änderungen. Nur in den erweiterten Einstellungen findet sich eine Option, mit der Sie das Seitenverhältnis des Videos von 4:3 in 16:9 und umgekehrt ändern können. Metadaten für den Clip In diesem Bereich können Sie einige Stammdaten zum Video eintragen, beispielsweise den Titel, den Autor, Copyright-Informationen oder auch, an welchem Ort das Video aufgenommen wurde. Manche Wiedergabeprogramme nutzen diese Informationen, in den meisten Abspielprogrammen sind die Daten aber nicht sichtbar.
146
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Erweiterte Videocodierungseinstellungen Wenn Sie schon etwas erfahrener mit der Videokonvertierung sind, können Sie hier noch ein paar grundlegende Einstellungen vornehmen.
Bild 2.40: Festlegen der erweiterten Videocodierungseinstellungen.
Wie HandBrake erlaubt auch Firefogg eine Änderung der Bitrate. Dieser Parameter hat eine unmittelbare Auswirkung auf die Videoqualität und – zur Erinnerung – bestimmt, wie viele Bits Speicherplatz pro Videosekunde maximal gespeichert werden können. Auch das 2-pass encoding kennen Sie schon von HandBrake. Wir empfehlen, diese Option zu aktivieren, falls Sie genug Zeit dafür haben. Der Codierungsvorgang wird ungefähr doppelt so lange dauern, resultiert aber in einem qualitativ höherwertigen Endergebnis. Eine genaue Beschreibung dazu, was diese Funktion macht, finden Sie im Abschnitt über HandBrake. In der Regel haben Sie keinen Grund, die anderen Optionen zu benutzen. Die Bildfrequenz wird üblicherweise vom Quellvideo übernommen, ebenso das Seitenverhältnis. Erweiterte Audiocodierungseinstellungen Hinter diesem langen Menünamen verbirgt sich nur eine Option: Audio im codierten Video auszuschalten. Sind Sie mit allen Ihren Einstellungen zufrieden, können Sie auf Ogg speichern klicken und einen Zielpfad sowie einen Dateinamen für das ins OGG Theora-Format konvertierte Video eingeben. Anschließend zeigt Firefogg einen Statusbalken und ein Vorschaufenster. Jetzt fragen Sie sich womöglich, warum Sie so viel über die Konvertierung von OGG Theora lernen mussten, obwohl es derzeit weder unter iOS noch unter Android verfügbar ist. Dazu gibt es zwei Gründe:
2.4 Audio und Video
147
•
Theora funktioniert auf einer Reihe von Desktop-Browsern und möglicherweise auch auf zukünftigen Versionen von Firefox Mobile und anderen mobilen Browsern und Betriebssystemen.
•
Mit Theora sind Sie lizenzrechtlich auf der sicheren Seite – auch nach 2016, wenn sich die Lizenzbedingungen für H.264 wieder ändern werden.
•
Alles, was Sie über die Konvertierung von OGG Theora mittels Firefogg gelernt haben, können Sie auch zur Codierung von WebM/VP8-Video nutzen.
Bild 2.41: Die Codierung des Videos nach OGG läuft.
WebM/VP8 mit Firefogg Glaubt man den Zusagen der Browserhersteller, steht WebM/VP8 eine große Zukunft bevor. Die meisten Betriebssysteme und Browserhersteller mit Ausnahme von Apple/Safari wollen VP8 als neuen Standard implementieren. Den Ankündigungen von Google auf der Entwicklerkonferenz zufolge wird auch eine der neuen Android-Versionen dieses Format unterstützen. Auch wenn WebM/VP8 noch eine sehr neue Technologie ist, wird sie dennoch bereits von Firefogg unterstützt. In den Voreinstellungen befinden sich schon zwei Optionen, um WebM-Video zu codieren. Bildbeispiel
Bezeichnung der Voreinstellungen
Dateigröße
WebM Web-Video mit VP8 (600 KBits/s bei 480 Pixeln maximaler Breite)
2,9 MByte
WebM Video (hochwertig) mit VP8 (1.080 Pixel maximale Breite)
9,9 MByte
Alles Andere können Sie wie bei der OGG Theora-Konvertierung einstellen.
148
2.5
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Geolocation-API
Die Geolocation-API – http://dev.w3.org/geo/api/spec-source.html – ermöglicht den Zugriff auf die geografische Position des Geräts via JavaScript. Da mobile Geräte häufig von nur einer Person benutzt werden, ist das in den meisten Fällen die Position des Eigentümers und ständigen Benutzers. Obwohl diese API des W3C aktuell im Status des »Editor Draft« vom 10. Februar 2010 vorliegt, wurde sie bereits umfassend und der Spezifikation entsprechend konform auf mehreren Plattformen implementiert. Dazu zählen iPhone OS 3+ sowie Android 2+. Zudem ist die Geolocation-API mit Sicherheit eine der faszinierendsten APIs. Der Zugriff auf den aktuellen Ort des Benutzers ermöglicht zahlreiche ortsbasierte Informationsdienste, die ohne den geskripteten Zugriff nur umständlich möglich wären. Location! Location! Location! Das hört man nicht nur immer vom Immobilienberater, sondern man sieht es auch in einer Vielzahl von mobilen Anwendungen und dank der Geolocation-API immer mehr auf mobilen Webseiten. Dabei ergeben ortsabhängige Dienste gerade mobil den wahrscheinlich größten Sinn: Der Anwender hat sein Mobiltelefon ständig dabei, und ohne umständlich seine Position anzugeben, kann nun sogar eine Webseite leicht herausfinden, wo sich der Benutzer befindet. Eine Vielzahl von bekannten Webdiensten nutzt die Möglichkeiten der Location-API. Viele Firmen und Dienste gründen ihr gesamtes Konzept auf der Tatsache, dass der aktuelle Ort eines Benutzers in einer mobilen Anwendung oder einer Seite vorhanden ist. Eines der ersten Mobiltelefone mit integriertem GPS, das eine große Masse erreichte, war das Nokia N95. Zahlreiche Symbian- and Java-Programme wurden um diese neue Funktionalität entwickelt. Für Webseiten blieb die Location-API aber bis Ende 2008 verschlossen. In den USA erschien das erste Android-Telefon, das T-Mobile G1, und bot erstmals Zugriff auf die aktuelle Position des Benutzers für Webseiten an. Den großen Durchbruch gab es aber am 17. Juni 2009: Zusammen mit dem iPhone 3GS wurde iPhone OS 3.0 veröffentlicht, das eben auch diese Funktionalität enthält.
Bild 2.42: Die Geolocation-API wird auch von Flickr benutzt, um Fotos in der Nähe des Benutzers anzuzeigen.
2.5 Geolocation-API
149
Die Fotoseite Flickr gehörte zu den ersten Webseiten, die gleich am 18. Juni 2009 (http://blog.flickr.net/de/2009/06/18/) dieses neue Feature seinen mobilen Nutzern unter m.flickr.com anbot. Und auch heute noch ist diese Funktion eine der beliebtesten Links auf Flickrs mobiler Seite. Gehen Sie einfach mit einem iPhone, einem Palm Pre oder einem Android-Telefon auf m.flickr.com und tippen Sie auf In der Nähe. Sie sehen nach zwei Sicherheitsabfragen (dazu gleich mehr) eine ganze Reihe von Fotos, die in Ihrer Nähe aufgenommen wurden. Weiter unten im Kapitel geben wir Ihnen auch noch einige Tipps dazu, wie Sie georeferenzierte Fotos von Flickr in Ihre Webseiten einbauen können. Seitdem hat sich die Funktion auf vielen mobilen Webdiensten ausgebreitet: Das reicht von sozialen Netzwerken über standortbasierte Spiele bis hin zu Immobilienseiten, die die passenden Wohnungen und Häuser gleich in der Nähe des Benutzers heraussuchen.
2.5.1
Privatsphäre und Sicherheit
Aus Sicht der Entwickler stellt die Positionsbestimmung des Benutzers einen immensen Wert dar. Allerdings darf nicht vergessen werden, dass diese Information selbstverständlich auch missbraucht werden kann. Die Spezifikation schreibt deshalb vor, dass der Benutzer der Positionsbestimmung ausdrücklich zustimmen muss. Das geschieht ab iPhone OS 3.0 durch einen modalen Dialog, der den Nutzer zwingt, zuzustimmen oder abzulehnen. Auf gängigen Android-basierten Geräten hingegen erscheint ein nicht modaler Dialog meist am unteren Rand des Bildschirms. Der Nutzer hat hier auch die Möglichkeit, diese Entscheidung für zukünftige Anfragen derselben Website zu speichern. Zwar kann die Entscheidung, der Ortsbestimmung zuzustimmen, zurückgesetzt werden, allerdings befindet sich die entsprechende Funktion drei Klicks tief in den Einstellungen des Browsers auf Android-Geräten und auch unter iOS einigermaßen versteckt in den allgemeinen Einstellungen. Ebenso interessant wie praktisch für Entwickler, aber auch erschreckend, ist, dass die Zustimmung nicht für eine bestimmte URL gilt, sondern komplett für eine Domain. Sobald Sie google.com also die Zustimmung zur Ortung geben und diese Entscheidung speichern, kann jede beliebige Seite unterhalb der google.com-Domain automatisch auf Ihre Position zugreifen. Sicherheitsabfragen unter iOS Unter iOS 4 gibt es ein interessantes Prinzip bei Sicherheitsabfragen für Webseiten, die die aktuelle Position des Anwenders im System anfragen. Der Nutzer wird insgesamt in drei kleinen, modalen Dialogfenstern um Zustimmung gebeten. Hier ein Beispiel mit m.flickr.com auf einem iPod touch, der noch nie eine Webseite mit Geolocation-APIUnterstützung aufgerufen hat: Falls zum ersten Mal im mobilen Safari-Browser eine Webseite nach der aktuellen Position des Benutzers fragt, muss der Anwender Safari den Zugriff auf diese Daten gestatten. Dieser Schritt ist logisch: Nur wenn der Browser erlaubten Zugriff auf die Geolocation-API und damit die aktuelle Nutzerposition hat, kann auch eine Webseite diese Daten erhalten.
150
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Bild 2.43: Safari den Zugriff gestatten.
Nachdem der Anwender dem Browser den Zugriff auf die Daten erlaubt hat, muss der Benutzer jetzt auch noch der jeweiligen Webseite den Zugriff auf die aktuelle Position gestatten. Ab iOS 4 und nachdem der Benutzer Safari mit den Zugriffsrechten ausgestattet hat, sehen Sie in der Titelleiste einen blauen Pfeil, der anzeigt, dass Safari jetzt gerade nach Positionsdaten fragt.
Bild 2.44: Flickr den Zugriff gestatten.
Vielleicht fragen Sie sich jetzt: Wieso drei Dialogfenster, dies waren doch nur zwei? Ganz einfach: Sobald der Benutzer auf Ihrer Webseite die Geolocation-Funktion ein zweites Mal aufruft, erscheint der letzte Dialog ebenfalls ein zweites Mal und muss nochmals vom Anwender bestätigt werden. Das ist ein Hilfsmittel, um sicherzugehen, dass die Erlaubnis beim ersten Mal nicht aus Versehen gegeben wurde. Natürlich kann der Anwender unter iOS 4 diese Erlaubnis auch zurücknehmen. Dabei kann er nicht nur einer bestimmten Webseite die Erlaubnis entziehen, sondern dem Browser insgesamt.
2.5 Geolocation-API
151
Bild 2.45: Von diesem Bildschirm aus lässt sich bestimmen, welches Programm Geoinformationen verwenden darf und welches nicht.
Zu dem Bildschirm gelangen Sie über Einstellungen/Allgemein und schließlich Ortungsdienste. Nachdem Sie Safari die Erlaubnis entzogen haben, hat keine der vorher benutzten und autorisierten Webseiten mehr Zugriff auf die Position des Benutzers. Auch wenn Sie die Einstellung für Safari wieder aktivieren, müssen dennoch alle Webseiten erneut die Dialogabfragen durchlaufen. Sicherheitsabfragen unter Android Die Abfragen für Geolocation-Anfragen von Webseiten unter Android sind etwas anders. Sie brauchen nicht erst dem Browser die Erlaubnis zu geben, sondern werden gefragt, sobald Sie eine Funktion auf der Webseite aufrufen, die einen Call zu der Geolocation-API initiiert. Dabei erscheint ein kleiner Dialog am unteren Rand der Webseite mit folgendem Text (wir verwenden wieder das Flickr-Beispiel): m.flickr.com möchte Ihren Standort in Erfahrung bringen. Sie können diesen Dialog mit Ablehnen schließen und den Zugriff nicht gestatten oder auf Standort freigeben tippen, um den Zugriff auf die Positionsdaten zu gewähren. Der Benutzer kann diese Auswahl als Voreinstellung speichern und wird dementsprechend den Dialog kein zweites Mal sehen. Anderenfalls wird der Dialog jedes Mal angezeigt. Wie unter iOS kann auch unter Android der Zugriff nur allen Webseiten und nicht einzelnen Seiten entzogen werden. Um zu den entsprechenden Einstellungsfenstern zu gelangen, tippen Sie einfach im Android-Browser auf Menü, dann auf Mehr und schließlich auf Einstellungen. In den Browsereinstellungen können Sie dann festlegen, ob der Browser generell den Standortzugriff für Webseiten ermöglichen soll oder nicht. Weiterhin finden Sie mit Standortzugriff löschen eine Funktion, mit der Sie allen bereits autorisierten Webseiten den Zugriff wieder entziehen.
152
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Fair Play gilt auch für Entwickler Auch dem Nutzer der Ortsinformationen, dem Entwickler, wird vorgeschrieben, wie mit diesen Informationen umzugehen ist. Freilich schützt das den Nutzer nicht vor Missbrauch, jedoch soll damit ein Standard geschaffen werden, der letztendlich Vertrauen schafft und die Nutzung von Ortsinformationen akzeptabel macht. Zusammenfassend kann gesagt werden, dass der Empfänger der Ortsinformationen die Daten nur für den angegebenen Zweck verwenden darf, sie auf Wunsch des Nutzers löscht und die Daten so vertraulich und sicher wie möglich gespeichert werden. Als Entwickler möchten wir Sie daher noch einmal eindringlich darauf hinweisen, dass aktuelle Positionen von Menschen extrem vertrauliche Daten sind und auch so behandelt werden sollten. Genug der langen Rede, tauchen wir ab in die technische Welt der Geolocation-API.
2.5.2
Feature Detection: Geolocation-API
Das Vorhandensein der Geolocation-API kann einfach überprüft werden. Das folgende Beispiel verdeutlicht das: var hasGeo function() { if (navigator.geolocation) return true; else return false; }; alert (hasGeo()) //true oder false
Das Vorhandensein der Eigenschaft geolocation Objects kann also ganz einfach im Navigator überprüft werden. Im gesamten HTML-Kontext einer Webseite sieht das wie folgt aus: HTML5 Geolocation <meta name "layout" content "webkit" /> <meta content "minimum scale 1.0, width device width, maximum scale 0.6667, user scalable no" name "viewport" /> <script src "js/modernizr 1.5.js" type "text/javascript"> <script>
2.5 Geolocation-API
(function my() { var $i
{};
$i.init function() { document.getElementById('message').innerHTML 'Vorhanden' : 'Nicht vorhanden'; };
$i.hasGeo() ?
$i.hasGeo function() { if (Modernizr.geolocation) return true; else return false; }; document.addEventListener("DOMContentLoaded", $i.init, false); }).call(); Erkennung mit Modernizr Powered by iWebKit
153
154
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Bild 2.46: Auf einem iPhone oder iPod touch sieht das Beispiel so aus.
Sollten Sie weiter HTML5-Features benutzen und sämtlichen Detection-Code nicht wiederholt schreiben wollen, empfehlen wir die Benutzung des Modernizr-Toolkits – http://www.modernizr.com. Modernizr ist eine recht kleine, kostenfreie und einfach gehaltene JavaScript-Bibliothek, die sich insbesondere dann anbietet, wenn Sie mehr als eines der neueren HTML5- und CSS 3-Features einsetzen wollen. Modernizr erstellt ein JavaScript-Objekt und liefert entweder false oder true für jedes der neuen HTML5-/CSS 3-Features zurück, je nachdem, ob das Feature unterstützt wird oder nicht. Um Modernizr einzubinden, müssen Sie die JavaScript-Bibliothek von der ModernizrWebseite herunterladen und auf Ihrem Webserver speichern. Anschließend muss die Bibliothek über die folgende Zeile in Ihren HTML-Code im head-Bereich eingebunden werden: <script src "modernizr 1.5.min.js" type "text/javascript">
Des Weiteren ist es erforderlich, dass das html-Tag das Attribut class "no-js" erhält:
Die Überprüfung sieht nach der Einbindung der Bibliothek wie folgt aus: //Einbindung des Modernizr var hasGeo function() { if (Modernizr.geolocation) return true; else return false; } alert (hasGeo()) //true oder false
Das neue JavaScript-Objekt heißt hier Modernizr.geolocation und liefert entweder den Wert true (Zugriff auf die Geolocation-API ist vorhanden) oder false (Geolocation-API wird vom Browser nicht unterstützt) zurück.
2.5 Geolocation-API
2.5.3
155
Arten der Positionsbestimmung
Die Geolocation-API unter navigator.geolocation ermöglicht sogenannte »OneShot«-Positionsanfragen sowie kontinuierliche Aktualisierungen. Die Funktionen der API sind: void getCurrentPosition(successCallback, in optional PositionErrorCallback errorCallback, in optional PositionOptions options); long watchPosition(in PositionCallback successCallback, in optional PositionErrorCallback errorCallback, in optional PositionOptions options); void clearWatch(in long watchId);
Die Funktionen getCurrentPosition und watchPosition unterscheiden sich nur darin, dass watchPosition kontinuierlich bei einer Änderung der Position die Callback-Funktionen aufruft. Wie deutlich die Änderung sein muss, um einen erneuten Aufruf auszulösen, ist hierbei der jeweiligen Implementierung überlassen und somit mit Vorsicht zu genießen (dazu später mehr). Der zurückgegebene long-Wert der watchPosition kann an die Funktion clearWatch übergeben werden, die dann die kontinuierliche Positionsbestimmung abschaltet.
2.5.4
Google Maps-API
Wenn wir an Karten im Internet denken, gibt es neben ein paar kleineren Anbietern eigentlich nur den großen Platzhirsch Google Maps. Google Maps ist der Standardkartenanbieter auf den meisten mobilen Plattformen, insbesondere mit den nativen Implementierungen unter iOS, Android und WebOS. Unter http://code.google.com/apis/ maps/ finden Sie eine Übersicht der verschiedenen APIs für Google Maps. Für unsere Zwecke werden wir uns mit der Maps-JavaScript-API beschäftigen.
Bild 2.47: Die Google Maps-API gibt es für JavaScript, Flash und auch für statische Bilder.
156
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Die JavaScript-API wurde im Mai 2010 in einer neuen Version veröffentlicht. Die dritte Version der Google Maps-API ist nicht nur schneller, sondern auch wesentlich mehr auf mobile Geräte mit dem Fokus auf iPhone und Smartphones mit Android-Betriebssystem ausgelegt. Die API wird über ein script-Tag im head-Bereich des HTML-Codes eingebunden: <script type "text/javascript" src "http://maps.google.com/maps/api/js?sensor true">
Im Gegensatz zur Version 2 der API erfordert die neue Version nicht mehr die Angabe eines API-Schlüssels. Neu ist allerdings der sensor-Parameter, der auch unbedingt mit angegeben werden muss. Er spezifiziert, ob die Position eines Benutzers über ein Gerät mit GPS-Empfänger bezogen wird oder nicht. Da wir in diesem Buch mit neuen, mobilen Betriebssystemen arbeiten, setzen wir den Parameter auf true. Die Google Maps-API benutzt die vom Benutzer gesetzte Spracheinstellung, um die verschiedenen Elemente, Bezeichnungen, Copyright-Informationen etc. auf der Karte anzuzeigen. In den meisten Fällen bedarf das keiner Änderung. Falls Sie jedoch eine Seite speziell für ein Land entwickeln und sicherstellen wollen, dass alle Elemente in der Google Maps-Ansicht in einer festgelegten Sprache angezeigt werden, können Sie den script-Aufruf um einen Sprachenparameter erweitern: <script type "text/javascript" src "http://maps.google.com/maps/api/js?sensor true&language de">
Alle Sprachelemente in der Google Maps-Ansicht werden nach diesem Aufruf auf Deutsch angezeigt, egal welche Sprache der Benutzer für seinen Browser eingestellt hat. Wichtiger als die Spracheinstellung (die in der Regel automatisch vom Browser übernommen wird) ist die Festlegung der Region, von der aus die meisten Benutzer die Seite mit der eingebundenen Google-Karte aufrufen. Mit dem folgenden script-Aufruf können Sie die Standardregion auf Deutschland setzen: <script type "text/javascript" src "http://maps.google.com/maps/api/js?sensor true®ion DE">
Dies macht dann einen Unterschied, wenn Sie beispielsweise nicht die Geokoordinaten zu Google Maps schicken, sondern Google Maps mit einem Städtenamen als Suchbegriff aufrufen. Wird die Region nicht angegeben, wird in der Regel angenommen, dass die USA die Standardregion ist. Gibt es einen passenden Städtenamen auch in den USA, beispielsweise »Dresden«, kann es passieren, dass das amerikanische Dresden im Bundesstaat Ohio angezeigt wird und nicht die sächsische Landeshauptstadt.
2.5.5
One-Shot-Positionsanfragen
Eine einfache One-Shot-Anfrage kann so erstellt werden: //Callback Funktion, wird aufgerufen, sobald Position vorhanden ist function showMap(position) { var lat position.coords.latitude; var lon position.coords.longitude;
2.5 Geolocation-API
157
} function handleError(error) { ... } // One Shot Anfrage var options {timeout:30000, maximumAge:300000, enableHighAccuracy:false}; navigator.geolocation.getCurrentPosition(showMap, handleError, options);
Obwohl der zweite und dritte Parameter – hier handleError, options – optional sind, sollte man auf die Implementierung nicht verzichten. showMap wird im obigen Beispiel aufgerufen, sobald der Benutzer der Ortsbestimmung zugestimmt hat und die Position festgestellt werden konnte. Ob das der Fall war, hängt auch von den Positionsoptionen ab, die als dritter Parameter übergeben werden. Falls eine Bestimmung nach Vorgabe der PositionOptions nicht möglich war, wird handleError aufgerufen und ein error-Objekt übergeben. Das PositionOptionsObjekt ist optional und kann folgende Eigenschaften enthalten: PositionOptions-Objekteigenschaften long timeout
Gibt die maximale Dauer der Positionsbestimmung an. Der Wert wird in Millisekunden angegeben, im obigen Beispiel also 30 Sekunden. Sobald diese Dauer überschritten ist, wird die ErrorCallback-Funktion aufgerufen. Die hier angegebene Dauer betrifft lediglich den Prozess der Ortsbestimmung. Falls der Nutzer also zunächst um die Zustimmung gefragt werden muss, hat der Bestimmungsprozess ab dem Zeitpunkt der Zustimmung den hier angegebenen Wert.
long maximumAge
Gibt an, ob auch eine zuvor bereits ermittelte Position zurückgegeben werden kann. Das bietet sich oftmals an, da so die Dauer der Ortsbestimmung deutlich reduziert werden kann, obgleich die Qualität der Position natürlich je nach Veränderung der realen Position deutlich abnimmt. Dieser Wert wird auch in Millisekunden angegeben, im obigen Beispiel wird also eine Position akzeptiert, die maximal 5 Minuten (300 Sekunden) alt ist.
boolean enableHighAccuracy
Da die meisten Geräte, die die Geolocation-API implementieren, mehrere Möglichkeiten zur Ortsbestimmung haben, wird über diese Eigenschaft angegeben, ob man die Methode benutzen möchte, die die größte Genauigkeit bietet. In den allermeisten Fällen wird hierdurch der GPS-Chip des Geräts bemüht, die Position zu bestimmen. Das kann je nach Gerät über 30 Sekunden dauern. Viel schneller, jedoch auch ungenauer, ist die Bestimmung per Wifi-Netzwerk in Reichweite oder IP-Adressen der WifiGateways.
158
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Ein erstes Beispiel einer One-Shot-Positionsanfrage:
HTML5 Geoposition One Shot Anfrage Markus Spiering / Sven Haiges
> One Shot Anfrage <meta name "layout" content "webkit" /> <meta content "minimum scale 1.0, width device width, maximum scale 0.6667, user scalable no" name "viewport" /> <script type "text/javascript" src "http://maps.google.com/maps/api/js?sensor true"> <script> (function my() { var $i $i.vars $i.init
{}; {}; function()
{ if ($i.hasGeo) { navigator.geolocation.getCurrentPosition($i.showLocation, $i.handleError, {timeout:30000, maximumAge:300000, enableHighAccuracy:true}) } else document.getElementById('message').innerHTML 'Geo Location API nicht verfügbar!'; }; $i.showLocation function(position) { document.getElementById('message').innerHTML 'latitude: ' + position.coords.latitude + ' / longitude: ' + position.coords.longitude + ' / accuracy: ' + position.coords.accuracy + 'meters (acquired '+new Date(position.timestamp)+')'; var latlng new google.maps.LatLng(position.coords.latitude, position.coords.longitude); var myOptions { zoom: 13, center: latlng, mapTypeId: google.maps.MapTypeId.ROADMAP };
2.5 Geolocation-API
// Kartenaufruf wird auf map Variable gelegt // var map new google.maps.Map(document.getElementById("map"), myOptions); } $i.handleError function(error) { var msgNode document.getElementById('message'); switch (error.code) { case error.TIMEOUT: msgNode.innerHTML + 'Zeit überschritten...'; navigator.geolocation.getCurrentPosition($i.showLocation, $i.handleError, {timeout:30000, maximumAge:300000}); break; case error.PERMISSION DENIED: msgNode.innerHTML + 'Benutzer hat Positionierung abgelehnt.'; break; case error.POSITION UNAVAILABLE: msgNode.innerHTML + 'Geoposition nicht verfügbar.'; break; } msgNode.innerHTML + }
'
Fehlermeldung: ' + error.message;
$i.hasGeo function() { if (navigator.geolocation) return true; else return false; }; document.addEventListener("DOMContentLoaded", $i.init, false); }).call(); One Shot Anfrage Powered by iWebKit
Das Beispiel zeigt, wie einfach man Ortsinformationen wie Breitengrad (latitude), Längengrad (longitude) und Genauigkeit (accuracy) durch eine einfache Geolocation-API-Anfrage erhält. Weiterhin wird eine Google Maps-Karte angezeigt, die genau auf die ermittelte Geoposition zentriert wird. Solange der Benutzer noch keinen Zugriff auf seine Geoposition erlaubt hat, werden weder Daten noch Karten angezeigt. Das Beispiel zeigt die Geopositionsdaten an und zentriert eine Google Maps-Karte auf der ermittelten Position.
Bild 2.48: Erteilen der Zugriffserlaubnis und Anzeige der Geopositionsdaten.
2.5.6
Ortungsmethoden
Man kann grob zwei Gruppen von Ortungsmethoden unterscheiden: die der netzwerkbasierten Ortung und die der gerätebasierten Ortung. Netzwerkbasierte Ortung bedeutet, dass beispielsweise die mobile Cell-ID der aktuell vom Gerät benutzten Mobilfunkbasisstation benutzt wird, um eine grobe Ortung durchzuführen. Da heutzutage Geräte mit WLAN weit verbreitet sind, kann auch über die aktuell benutzte Gateway-IPAdresse sowie die Stärke der empfangenen WLAN-Netze eine Ortung durchgeführt werden, die oftmals schon recht genau ist. Mit gerätebasierter Ortung ist praktisch fast ausschließlich die Ortung per GPS-Chips gemeint. Hier empfängt der in das Gerät ein-
2.5 Geolocation-API
161
gebaute GPS-Chip die Satellitensignale mehrerer GPS-Satelliten und kann dadurch die Position auf wenige Meter genau bestimmen. Die netzwerkbasierten Ortungsmethoden sind meist schnell, ungenau und verbrauchen wenig Energie. Die gerätebasierten Ortungsmethoden sind langsamer, besonders bei der ersten Ortungsanfrage, jedoch deutlich genauer und verbrauchen leider – der GPS-Chip muss mit Energie versorgt werden – auch deutlich mehr Strom. Wenn der PositionOptions-Parameter nicht angegeben wird, ist enableHighAccuracy false, timout unbegrenzt (Infinity) und maximumAge 0. Auf das PositionOptionsObjekt wird später noch genauer eingegangen. Bei erfolgreicher Bestimmung der Position wird die showMap-Funktion unseres Beispiels aufgerufen. An diese Funktion wird ein Objekt mit folgenden Eigenschaften übergeben: Coordinates coords Die coords-Eigenschaft verweist auf ein weiteres Objekt, das die eigentlichen Positionsdaten laut World Geodic System (WGS84) enthält. Eigenschaften, deren Datentyp in der Tabelle unten mit ? angegeben ist, sind optional, d. h., die jeweilige Implementierung muss das nicht unterstützen. Inhalte des coords-Objekts double latitude
Geografische Koordinaten laut WGS84. (WGS84 ist das am weitesten verbreitete Koordinatensystem und wird beispielsweise durch GPS unterstützt.)
double longitude
Geografische Koordinaten laut WGS84.
double accuracy
Die Genauigkeit der Koordinaten, angegeben in Meter. Der Wert 75 gibt an, dass die Position, die durch latitude und longitude angegeben wurde, um bis zu 75 Meter von der realen Position abweichen kann.
double? altitude
Die Höhe in Metern oberhalb des WGS84-Ellipsoids. Falls die Implementierung das nicht unterstützt, wird null zurückgegeben.
double? altitudeAccuracy
Genauigkeit der Höhenangabe. Eine mögliche Abweichung wird in Metern angegeben. Falls nicht unterstützt, wird null zurückgegeben.
double? heading
Die aktuelle Fahrtrichtung, angegeben in Grad relativ zum Norden im Uhrzeigersinn. Null, falls nicht vorhanden.
double? speed
Falls vorhanden, die aktuelle Geschwindigkeit in Metern pro Sekunde. ansonsten null.
DOMTimeStamp timestamp Ein DOMTimeStamp, der per new Date(timestamp) am einfachsten in ein leserliches Datum verwandelt wird. Der Timestamp gibt an, wann genau die in coords gespeicherten Informationen erhoben wurden.
162
Kapitel 2 – HTML5 in der mobilen Webentwicklung
2.5.7
PositionOptions genauer betrachtet
Als dritter Parameter kann sowohl an getCurrentPosition als auch an watchPosition ein Objekt übergeben werden, das die vom Entwickler erwartete Position genauer definiert. Die Kombination von enableHighAccuracy, timeout und maximumAge kann unter anderem dazu verwendet werden, eine aktuelle Positionierung zu erzwingen. Schauen wir uns das anhand eines Beispiels an; // One Shot Anfrage, schlechte Idee ... var options {timeout:0, maximumAge:0, enableHighAccuracy:true}; navigator.geolocation.getCurrentPosition(showMap, handleError, options);
Eine so durchgeführte Anfrage an die Geolocation-API wird mit höchster Wahrscheinlichkeit fehlschlagen. timeout 0 gibt an, dass das Ergebnis der Positionierung sofort verfügbar sein soll. Dies ist jedoch nur dann möglich, wenn kein neuer Positionierungsprozess gestartet wird, denn egal, welche Methode benutzt wird, ein timeout 0 ist nicht machbar. Da gleichzeitig maximumAge 0 und enableHighAccuracy true angegeben werden, werden jedoch explizit frühere Ergebnisse abgelehnt, und die genaueste und damit zeitintensivste Methode wird ausgewählt. Äußerst vielversprechend ist dagegen dieses Beispiel: var options {timeout:30000, maximumAge:0, enableHighAccuracy:false}; navigator.geolocation.getCurrentPosition(showMap, handleError, options);
Das Gerät wird in diesem Fall – sofern unterstützt – die Positionsbestimmung per IPAdresse oder vorhandenen WiFi-Netzwerken auswählen, da enableHighAccuracy false ist. Durch maximumAge 0 wird ein neuer Bestimmungsprozess ausgelöst, der mit einem timeout 30000 und somit 30 Sekunden jedoch üppig bemessen ist. Folglich sieht ein Beispiel für eine möglichst exakte und aktuelle Position unter Inkaufnahme einer längeren Bestimmungsdauer so aus: var options {timeout:60000, maximumAge:0, enableHighAccuracy:true}; navigator.geolocation.getCurrentPosition(showMap, handleError, options);
Es können natürlich auch mehrere Anfragen zeitlich kombiniert werden. Beispielsweise kann eine Webapplikation zunächst eine Anfrage durchführen, die in aller Regel schnell, jedoch auch ungenau beantwortet wird. Sobald das erste Ergebnis vorliegt, kann eine zweite, genauere Anfrage gestartet werden, die dann im Hintergrund arbeitet. Der Benutzer interagiert dadurch direkt mit der Applikation, seine Position wird nach und nach genauer definiert. Ein weiteres Beispiel demonstriert das: ... var $i $i.vars
{}; {first:true};
//wird aufgerufen, sobald DOM ready $i.init function() { if (Modernizr.geolocation) {
2.5 Geolocation-API
163
//erste Anfrage, wir nehmen (fast) alles navigator.geolocation.getCurrentPosition($i.showLocation, $i.handleError, {timeout:30000, maximumAge:600000, enableHighAccuracy:false}); } }; $i.showLocation function(position) { var msg 'latitude: ' + position.coords.latitude + ' / longitude: ' + position.coords.longitude + ' / accuracy: ' + position.coords.accuracy + 'meters (acquired '+new Date(position.timestamp)+')'; if ($i.vars.first) { document.getElementById('message').innerHTML msg; $i.vars.first false; //zweite Anfrage, nun mit hoher Genauigkeit und erzwungener Aktualität navigator.geolocation.getCurrentPosition($i.showLocation, $i.handleError, {timeout:120000, maximumAge:0, enableHighAccuracy:true}); } else document.getElementById('message').innerHTML + ('
' + msg); var map new google.maps.Map2(document.getElementById("map")); map.setCenter(new google.maps.LatLng(position.coords.latitude, position.coords.longitude), 13);
} ...
In obigem Beispiel wird also zuerst eine Anfrage mit dem PositionOptions-Objekt gestartet, die in der Regel zügig beantwortet wird: {timeout:30000, maximumAge:600000, enableHighAccuracy:false}
Sobald das Ergebnis vorliegt, wird eine zweite Anfrage gestartet, diesmal geben wir uns nicht so einfach zufrieden: {timeout:120000, maximumAge:0, enableHighAccuracy:true}
Auf der Demoseite sieht das dann folgendermaßen aus: HTML5 <meta name "layout" content "webkit" /> <style type "text/css" media "screen">
164
Kapitel 2 – HTML5 in der mobilen Webentwicklung
<script src "${resource(dir:'js',file:'modernizr 1.1.min.js')}" type "text/javascript"> <script type "text/javascript" src "http://www.google.com/jsapi?key ABQIAAAAk6AH6TdjmGE76Sg VZ hzRSYyF8ynozO6JFpZ6CDrLxUILeJ4BRcA2RZA26oyr7iw013JXdKrPSuCw">
<script> (function my() { var $i $i.vars
{}; {first:true};
$i.init function() { if (Modernizr.geolocation) { navigator.geolocation.getCurrentPosition($i.showLocation, $i.handleError, {timeout:30000, maximumAge:600000, enableHighAccuracy:false}); } else document.getElementById('message').innerHTML 'Sorry, no Geolocation API available!'; }; $i.showLocation function(position) { var msg 'latitude: ' + position.coords.latitude + ' / longitude: ' + position.coords.longitude + ' / accuracy: ' + position.coords.accuracy + 'meters (acquired '+new Date(position.timestamp)+')'; if ($i.vars.first) { document.getElementById('message').innerHTML msg; $i.vars.first false; navigator.geolocation.getCurrentPosition($i.showLocation, $i.handleError, {timeout:120000, maximumAge:0, enableHighAccuracy:true}); } else document.getElementById('message').innerHTML + ('
' + msg); var map new google.maps.Map2(document.getElementById("map")); map.setCenter(new google.maps.LatLng(position.coords.latitude, position.coords.longitude), 13);
2.5 Geolocation-API
165
} $i.handleError { var msgNode
function(error) document.getElementById('message');
switch (error.code) { case error.TIMEOUT: msgNode.innerHTML + 'timed out...'; navigator.geolocation.getCurrentPosition($i.showLocation, $i.handleError, {timeout:30000, maximumAge:300000}); break; case error.PERMISSION DENIED: msgNode.innerHTML + 'user declined positioning'; break; case error.POSITION UNAVAILABLE: msgNode.innerHTML + 'position not available'; break; } msgNode.innerHTML +
'
error message: ' + error.message;
} //document.addEventListener("DOMContentLoaded", $i.init, false); google.load("maps", "2.x"); google.setOnLoadCallback($i.init); }).call();
Zunehmende Genauigkeit Powered by iWebKit
166
Kapitel 2 – HTML5 in der mobilen Webentwicklung
2.5.8
Error-Callbacks
Die Implementierung eines Error-Handlers ist zwar optional, allerdings kann, wie Sie ja schon anhand der Beispiele gesehen haben, so einiges schiefgehen. Zunächst einmal braucht der Nutzer der Ortsbestimmung überhaupt nicht zuzustimmen. Und selbst wenn er die Zusage gegeben hat, kann eine Bestimmung der aktuellen Position aus einer Vielzahl technischer Gründe nicht möglich sein. Aus diesem Grund kann sowohl bei watchPosition also auch bei getCurrentPosition ein Error-Handler angegeben werden. Ein Error-Handler verweist per Referenz auf eine JavaScript-Funktion. An die Funktion wird im Fehlerfall ein error-Objekt übergeben. Das folgende Beispiel zeigt eine solche Funktion: function handleError(error) { var msgNode document.getElementById('message'); switch (error.code) { case error.TIMEOUT: msgNode.innerHTML + 'timed out...'; //nochmal versuchen? break; case error.PERMISSION DENIED: msgNode.innerHTML + 'user declined positioning'; break; case error.POSITION UNAVAILABLE: msgNode.innerHTML + 'position not available'; break; } }
Das an die Funktion übergebene error-Objekt enthält drei konstante Werte, die Fehlerfälle. Anhand des Property-Codes kann festgestellt werden, welcher dieser Fälle eingetreten ist. Fehlerfall
Beschreibung
TIMEOUT
Die Position konnte nicht festgestellt werden, da der im PositionOptions-Objekt angegebene Timeout überschritten worden ist.
PERMISSION_DENIED
Der Benutzer hat der Positionsbestimmung nicht zugestimmt.
POSITION_UNAVAILABLE
Die Position kann derzeit nicht festgestellt werden. Beispielsweise ist der Nutzer nicht online (keine Wifi-Netzwerke in Reichweite, keine Internetverbindung), oder die GPS-Satelliten können nicht erreicht werden.
2.5 Geolocation-API
167
Das error-Objekt enthält zudem das Property message, das eine kurze Beschreibung (auf Englisch) des aufgetretenen Fehlers enthält. Dieser Hinweis sollte nur während der Entwicklung in der UI angezeigt werden, da er nicht lokalisiert ist. Je nach eingetretenem Fall sollte der Entwickler entsprechend mit der Situation umgehen. Falls ein Timeout eintritt, kann beispielsweise ein neuer Ortungsversuch mit höherem Timeout und/oder geringerer Genauigkeit unternommen werden. Falls der Nutzer der Positionsbestimmung nicht zugestimmt hat, kann die Applikation auf eine Standardposition zurückfallen oder dem Nutzer eine Erklärung dafür geben, wieso die angefragte Position zur Nutzung dieser Webseite notwendig ist. Dem Nutzer kann dann auch die Möglichkeit gegeben werden, erneut einer Anfrage zuzustimmen.
2.5.9
WatchPosition – ständige Positionsupdates
Mittels der watchPosition-Methode der Geolocation-Schnittstelle kann eine Applikation per JavaScript ständig aktualisierte Positionierungen empfangen. Je nach Implementierung unterschiedlich ist dabei die Häufigkeit, mit der diese Methode den Callback-Handler aufruft. Schauen wir uns zunächst aber ein einfaches Beispiel an, das der One-Shot-Anfrage sehr ähnlich ist: //Callback Funktion, wird aufgerufen, sobald Position vorhanden ist function showMap(position) { var lat position.coords.latitude; var lon position.coords.longitude; } function handleError(error) { ... } var options var watchId options);
{timeout:30000, maximumAge:300000, enableHighAccuracy:true}; navigator.geolocation.watchPosition(showLocation, handleError,
Im Prinzip nichts bahnbrechend Neues, allerdings gibt die watchPosition-Methode eine numerische ID zurück, die zur Beendigung der ständigen Ortung benutzt werden kann. Um diese ständige Ortung also zu beenden, wird die clearWatch-Methode aufgerufen: navigator.geolocation.clearWatch(watchID);
clearWatch hat keinen Rückgabewert. Falls die übergebene ID vorhanden ist, wird die
ständige Ortung im Zusammenhang mit dieser ID sofort beendet. Es bietet sich also an, die ID, die von watchPosition zurückgegeben wird, umgehend in einer Variablen zu speichern. Damit kann dann später die Operation abgebrochen werden, falls die Ortung nicht mehr erwünscht ist. Leider gibt die Geolocation-API-Spezifikation nicht vor, wie oft die showMap-CallbackMethode aus unserem Beispiel aufgerufen werden soll. Somit kann es passieren, dass Ihre Applikation mit Aufrufen überhäuft wird. Es bietet sich daher an, innerhalb der
168
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Callback-Methode einen Check durchzuführen und die eigentliche Logik nur dann auszuführen, wenn beispielsweise einige Sekunden vergangen sind. Dies kann so implementiert werden: var usedCallbacks 0; var callbacks 0; var lastUpdate null; function showLocation(position) { callbacks++; document.getElementById('message1').innerHTML if (lastUpdate) { var differenceInSeconds
$i.vars.callbacks;
(new Date().getTime()
lastUpdate) /
1000; //wenn weniger als 15 Sekunden vergangen sind, return if (differenceInSeconds < 15) return; } //es sind mehr als 15 sekunden vergangen, update lastUpdate new Date().getTime(); usedCallbacks++; document.getElementById('message2').innerHTML $i.vars.usedCallbacks; ... }
Die folgende kleine Beispielanwendung zeigt uns, wie oft die showPosition-CallbackFunktion tatsächlich aufgerufen wird:
HTML5 Geo Position watchPosition Markus Spiering / Sven Haiges
> watchPosition <meta name "layout" content "webkit" /> <meta content "minimum scale 1.0, width device width, maximum scale 0.6667, user scalable no" name "viewport" /> <script type "text/javascript" src "http://maps.google.com/maps/api/js?sensor true">
2.5 Geolocation-API
169
<script> (function my() { var $i {}; $i.vars {}; $i.vars.callbacks 0; $i.vars.usedCallbacks 0; $i.vars.lastUpdate null; $i.init function() { if ($i.hasGeo) { $i.vars.watchID navigator.geolocation.watchPosition($i.showLocation, $i.handleError, {timeout:30000, maximumAge:300000, enableHighAccuracy:true}); document.getElementById('stop').addEventListener('click', function(event) { if ($i.vars.watchID ! null) { navigator.geolocation.clearWatch($i.vars.watchID); alert('Cleared watch with ID:' +$i.vars.watchID); $i.vars.watchID null; this.value 'Beobachten starten'; } else { $i.vars.watchID navigator.geolocation.watchPosition($i.showLocation, $i.handleError, {timeout:30000, maximumAge:300000, enableHighAccuracy:true}); this.value 'Beobachten stoppen'; } }, true); } else document.getElementById('message').innerHTML 'Geo Location API nicht verfügbar!'; }; $i.showLocation function(position) { $i.vars.callbacks++; document.getElementById('message1').innerHTML $i.vars.callbacks; if (!$i.vars.map) { var latlng new google.maps.LatLng(position.coords.latitude, position.coords.longitude); var myOptions {
170
Kapitel 2 – HTML5 in der mobilen Webentwicklung
zoom: 17, center: latlng, mapTypeId: google.maps.MapTypeId.ROADMAP }; $i.vars.map new google.maps.Map(document.getElementById("map"), myOptions); } if ($i.vars.lastUpdate) { var differenceInSeconds (new Date().getTime() $i.vars.lastUpdate) / 1000; if (differenceInSeconds < 15) return; } $i.vars.lastUpdate new Date().getTime(); $i.vars.usedCallbacks++; document.getElementById('message2').innerHTML $i.vars.usedCallbacks; // Create our "tiny" marker icon var image 'http://www.google.com/intl/en us/mapfiles/ms/micons/blue dot.png'; var markerLatLng new google.maps.LatLng(position.coords.latitude, position.coords.longitude); var beachMarker new google.maps.Marker({ position: markerLatLng, map: $i.vars.map, icon: image });
} $i.handleError { var msgNode
function(error) document.getElementById('message');
switch (error.code) { case error.TIMEOUT: msgNode.innerHTML + 'Zeit überschritten...'; break; case error.PERMISSION DENIED: msgNode.innerHTML + 'Benutzer hat Positionierung abgelehnt.'; break; case error.POSITION UNAVAILABLE: msgNode.innerHTML + 'Geo Position nicht verfügbar.';
2.5 Geolocation-API
171
break; } msgNode.innerHTML +
'
Fehlermeldung: ' + error.message;
} $i.hasGeo function() { if (navigator.geolocation) return true; else return false; }; document.addEventListener("DOMContentLoaded", $i.init, false); }).call();
watchPosition Powered by iWebKit
Es werden sowohl sämtliche Callbacks wie auch die tatsächlich für die Logik der Applikation benutzten Callbacks hochgezählt. Wird eine Position benutzt, wird auf einer Google Map ein Marker eingetragen. Das folgende Bild zeigt die Wanderung des Autors über den Zeitraum von 8 x 15 Sekunden in der Nähe des Yahoo!-Campus in Sunnyvale, CA.
172
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Im linken Bild sehen Sie eine 120-sekündige Wanderung auf dem Yahoo!-Campus in Sunnyvale, CA. Die Anzeige erfolgt hier mit der Google Maps-API Version 2. Die daneben im Codebeispiel verwendete Google Maps-API Version 3 bietet dem Benutzer auch die Möglichkeit, in verschiedene Ansichten umzuschalten – hier eine Wanderung durch das Wohngebiet in Satellitenbildansicht.
Bild 2.49: Wanderung auf dem Yahoo!-Campus (links) und im Wohngebiet.
Die beiden Zahlen neben den Text-Callbacks stellen die Anzahl sämtlicher Aufrufe der showPosition-Funktion und die tatsächlich benutzten Aufrufe dar (je 15 Sekunden wurde eine Position benutzt). Das bedeutet also grob ein Update pro Sekunde. Natürlich kann das je nach Implementierung und benutzter Bestimmungsmethode schwanken.
2.5.10 Reverse Geocoding mit Google Maps-API Über die Geolocation-API erhalten Sie – vereinfacht ausgedrückt – die latitude und longitude des Geräts. Das ist häufig die Information, die man benötigt, um beispielsweise den aktuellen Ort via Google Maps anzeigen zu können. Oftmals möchte man jedoch die nächstmögliche mit dieser Position in Verbindung gebrachte Adresse haben. Dazu gibt es sogenannte Reverse Geocoding Services. Ein prominentes Beispiel ist die Google Maps-Geocoding-API, die sich sowohl zur Umwandlung von Adressen in latitude/longitude als auch zum Reverse Geocoding, also dem Auflösen eines latitude/longitude-Paars in eine Adresse, eignet. Die Benutzung der API ist recht einfach: function showAddress function(response) { if (!response || response.Status.code ! 200) { alert("Status Code:" + response.Status.code); } else { var place response.Placemark[0]; document.getElementById('message').innerHTML '
' + 'orig latlng:' + response.name + '
' +
2.5 Geolocation-API
173
'latlng:' + place.Point.coordinates[1] + "," + place.Point.coordinates[0] + '
' + 'Status Code:' + response.Status.code + '
' + 'Status Reqüst:' + response.Status.reqüst + '
' + 'Address:' + place.address + '
' + 'Accuracy:' + place.AddressDetails.Accuracy + '
' + 'Country code: ' + place.AddressDetails.Country.CountryNameCode; } } var latlon new google.maps.LatLng(position.coords.latitude, position.coords.longitude); new GClientGeocoder().getLocations(latlon, showAddress);
Auf einem mobilen Gerät sieht das innerhalb einer kleinen Demoapplikation folgendermaßen aus: Zuerst ermittelt die Beispielanwendung die Geoposition des Benutzers und zeigt sie wie in den vorangegangenen Beispielen in Breiten- und Längengrad an. Nach dem Aufruf des Geocoders wissen Sie, dass der Breitengrad 37.799 und der Längengrad -122.417 zu dieser Adresse gehören: 1129 Union St, San Francisco, Kalifornien, Postleitzahl 94109, Vereinigte Staaten.
Bild 2.50: Beispiel eines Reverse Geocoding.
Wie auch zuvor finden Sie anschließend wieder den gesamten Code für ein ReverseGeocoding-Beispiel:
HTML5 Geo Position Reverse Geocoding Markus Spiering / Sven Haiges
> Reverse Geo Coding
174
Kapitel 2 – HTML5 in der mobilen Webentwicklung
<meta name "layout" content "webkit" /> <meta content "minimum scale 1.0, width device width, maximum scale 0.6667, user scalable no" name "viewport" /> <script type "text/javascript" src "http://maps.google.com/maps/api/js?sensor true"> <script> (function my() { var $i $i.vars
{}; {};
$i.init function() { if ($i.hasGeo) { navigator.geolocation.getCurrentPosition($i.showLocation, $i.handleError, {timeout:30000, maximumAge:300000, enableHighAccuracy:true}) } else document.getElementById('message').innerHTML 'Geo Location API nicht verfügbar!'; }; $i.showLocation function(position) { document.getElementById('message').innerHTML 'latitude: ' + position.coords.latitude + ' / longitude: ' + position.coords.longitude + ' / accuracy: ' + position.coords.accuracy + 'meters (acquired '+new Date(position.timestamp)+')'; var latlng new google.maps.LatLng(position.coords.latitude, position.coords.longitude); vargeocoder new google.maps.Geocoder(); geocoder.geocode({'latLng': latlng}, function(results, status) { if (status google.maps.GeocoderStatus.OK) { if (results[0]) { $i.showAddress(results[0]) //0 most accurate } } else { alert("Reverse Geocoding nicht möglich : " + status); } }); }
2.5 Geolocation-API
175
$i.showAddress function(result) { document.getElementById('message').innerHTML '
' + 'Geo Koordinaten: ' + result.geometry.location + '
' + 'Formatierte Adresse:' + result.formatted address + '
'; } $i.handleError { var msgNode
function(error) document.getElementById('message');
switch (error.code) { case error.TIMEOUT: msgNode.innerHTML + 'Zeit überschritten...'; navigator.geolocation.getCurrentPosition($i.showLocation, $i.handleError, {timeout:30000, maximumAge:300000}); break; case error.PERMISSION DENIED: msgNode.innerHTML + 'Benutzer hat Positionierung abgelehnt.'; break; case error.POSITION UNAVAILABLE: msgNode.innerHTML + 'Geo Position nicht verfügbar.'; break; } msgNode.innerHTML + }
'
Fehlermeldung: ' + error.message;
$i.hasGeo function() { if (navigator.geolocation) return true; else return false; }; document.addEventListener("DOMContentLoaded", $i.init, false); }).call(); Reverse Geo Coding Powered by iWebKit
2.5.11 Georeferenzierte Fotos von Flickr einbinden Eine der reichsten Quellen für georelevante Inhalte ist die Foto-Sharing-Seite Flickr – www.flickr.com. Die mittlerweile zu Yahoo! gehörende Seite hat nicht nur circa 5 Milliarden Fotos zu bieten, sondern auch eine offene und einfach zu verwendende Programmierschnittstelle (API), um Daten von Flickr in eigenen Programmen oder Webseiten zu verwenden. Insbesondere für mobile Webseiten und Anwendungen ist das interessant, da Flickr den weltweit größten Pool an georeferenzierten Fotos im Internet bietet. Das kleine Beispiel, das wir Ihnen jetzt vorstellen, ermittelt auf Abruf des Benutzers die aktuelle Position, ruft dann die Flickr-API auf und fragt nach Fotos, die in einem bestimmten Umkreis dieser Position aufgenommen wurden. Besucher einer fremden Stadt beispielsweise können auf einen Blick erkennen, welche Sehenswürdigkeiten und Plätze um sie herum sind. Das Ganze kann, wie im Beispiel gezeigt, auch mit Google Maps verbunden werden, um die Position der einzelnen Fotos auch auf einer Karte sichtbar zu machen. Neben dieser praktischen Anwendung zeigt Ihnen das Beispiel auch, wie Sie aus JavaScript eine Web-API aufrufen, mit empfangenen Daten dieser API umgehen und sie verwenden können.
Bild 2.51: Mash-up von Flickr-Fotos und Google Maps anhand der aktuellen Position eines Benutzers.
2.5 Geolocation-API
177
Um Daten von Flickr innerhalb einer Webseite oder Anwendung nutzen zu können, müssen Sie sich bei der Seite anmelden und einen API-Schlüssel beantragen. Sie können die Anmeldung auf www.flickr.com mit einer Yahoo!-ID durchführen und einen FlickrAccount erstellen oder eine neue Yahoo!-ID registrieren. Sobald Sie Ihren eigenen Flickr-Account haben, können Sie nicht nur Fotos und Videos hochladen, sondern auch die API nutzen. Um einen API-Schlüssel zu beantragen, rufen Sie am besten die folgende Adresse für den Flickr App Garden auf: www.flickr.com/services.
Bild 2.52: Fertige Web Apps, die mit der Flickr-API erstellt wurden, können im App Garden veröffentlicht werden.
Im App Garden sind viele Hundert Anwendungen und Webseiten gelistet, die die FlickrAPI verwenden – ein guter Start, um nicht nur einen Schlüssel zu beantragen, sondern auch, um sich ein paar Ideen zu holen. Einen API-Schlüssel beantragen Sie mit einem Klick auf Beantragen Sie einen API-Schlüssel auf der rechten Seite. Das bringt Sie zu einer Seite, auf der Sie entscheiden müssen, ob Sie einen nicht kommerziellen oder einen kommerziellen API-Schlüssel benötigen. Einen nicht kommerziellen API-Schlüssel erhalten Sie sofort, einen kommerziellen Schlüssel hingegen erhalten Sie nur nach Prüfung durch Flickr. Die genauen Bedingungen für einen kommerziellen API-Schlüssel entnehmen Sie der Webseite, aber wann immer Sie eine Anwendung oder Webseite mit Flickr-Inhalten oder Flickr-Funktionalität planen, die entweder verkauft werden soll oder für eine größere Firma oder Marke erstellt wird, ist in der Regel ein kommerzieller Schlüssel erforderlich. Allerdings benötigen Sie den kommerziellen Schlüssel in diesen Fällen immer erst dann, wenn Sie die Integration oder die Webseite veröffentlichen. Für den Zeitraum der Entwicklung reicht stets der nicht kommerzielle Schlüssel, sofern das Produkt noch nicht veröffentlicht wird. Private Webseiten oder private Projekte brauchen in der Regel keinen kommerziellen Schlüssel. Nähere Informationen finden Sie im Flickr App Garden.
178
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Bild 2.53: Flickr unterscheidet zwischen kommerziellen und nicht kommerziellen APISchlüsseln. Nicht kommerzielle Schlüssel genügen während der Entwicklungsphase und werden sofort ausgestellt.
Wie bereits erwähnt: Selbst wenn Ihre Anwendung einen kommerziellen Schlüssel benötigt, können Sie bei der Entwicklung mit einem nicht kommerziellen Schlüssel arbeiten. Diesen beantragen Sie mit einem Klick auf NICHT KOMMERZIELLEN SCHLÜSSEL BEANTRAGEN und geben auf der folgenden Seite einige Informationen zu Ihrem geplanten Projekt ein:
Bild 2.54: Bevor die API ausgestellt wird, fragt Flickr nach einigen Angaben zur geplanten Anwendung oder Webseite.
2.5 Geolocation-API
179
Wollen Sie die Angaben an Flickr übermitteln, lesen Sie sich bitte vorher die Nutzungsbedingungen der Flickr-API durch. Flickr legt großen Wert darauf, dass die Rechte der Fotos beim Fotografen liegen und diese Rechte auch von jedem Nutzer der API respektiert werden. Nachdem Sie die Nutzungsbedingungen gelesen und die richtigen Häkchen im Formular gesetzt haben, können Sie es an Flickr übermitteln und bekommen sofort, ohne weitere Überprüfung, einen neuen API-Schlüssel ausgestellt. Dabei erhalten Sie den API-Schlüssel sowie einen geheimen API-Schlüssel.
Bild 2.55: Für unser Beispiel benötigen Sie nur den normalen APISchlüssel, nicht den geheimen Schlüssel.
Alle API-Anfragen bei Flickr benötigen den normalen API-Schlüssel. Der geheime APISchlüssel wird lediglich bei API-Anfragen gebraucht, die auf persönliche Daten eines Flickr-Benutzers zugreifen. Für unser Beispiel werden wir nur öffentlich verfügbare Fotos über eine Suchanfrage abfragen und darstellen. Dafür reicht der normale APISchlüssel aus. Als Ausgangscode verwenden wir für das Beispiel die One-Shot-Anfrage, um die Position des Benutzers herauszufinden. Wie im One-Shot-Beispiel wird auch hier die Position in den Variablen position.coords.longitude und position.coords.latitude gespeichert. Die Google Maps-Karte wird ebenfalls zentriert um die Position des Benutzers aufgerufen – nahezu Zeile für Zeile wie im vorhergehenden One-Shot-Beispiel. Anschließend kommt die Flickr-API ins Spiel. Um sie benutzen zu können, müssen wir den API-Schlüssel als Variable definieren: var apiKey
'Flickr API Key';
Als API-Call werden wir die Methode flickr.photos.search verwenden, die einfach die Bildsuchfunktion auf Flickr widerspiegelt. Sie können nicht nur nach Begriffen suchen, sondern über diese API auch eine Geoposition angeben und dann nach Fotos (oder auf Wunsch auch Videos oder Fotos und Videos) suchen, die in einem angegebenen Umkreis aufgenommen wurden: var requestURL 'http://api.flickr.com/services/rest/?method flickr.photos.search&api key ' + apiKey + '&media photos&lat ' + position.coords.latitude + '&lon ' +
180
Kapitel 2 – HTML5 in der mobilen Webentwicklung
position.coords.longitude + '&radius 2&extras geo%2Curl sq&format json&jsoncallback apiCallback&per page 20';
Mit den Ergebnissen von der Flickr-API wird dann in einem Fotocontainer für jedes empfangene Bild ein Thumbnail angezeigt: imgElement document.createElement('img'); imgElement.src photos[i].url sq imgElement.hspace 5 imgElement.vspace 5 imgElement.alt photos[i].title; photoContainer.appendChild(imgElement);
Und dazu wird pro Foto noch eine Markierung auf die Google Maps-Karte gesetzt: new google.maps.Marker({ position: new google.maps.LatLng(photos[i].latitude, photos[i].longitude), map: $i.map, title: photos[i].title});
Insgesamt ist das One-Shot-Beispiel nur um wenige Zeilen Code erweitert worden, bietet aber auf einmal nicht nur eine Landkarte, sondern auch völlig neue und relevante Inhalte. Nach dem Aufrufen der Webseite wird erst die Position des Benutzers abgefragt. Anschließend wird die Google Maps-Karte angezeigt, die Flickr-API aufgerufen und abhängig von den zurückkommenden Daten pro Bild ein kleines Thumbnail gezeigt sowie eine Markierung auf die Google-Karte gesetzt. Hier ist das Ergebnis in Form einer kompletten ausgeklappten Seite:
Bild 2.56: Mash-up von Flickr-Fotos und Google Maps anhand der aktuellen Position eines Benutzers.
2.5 Geolocation-API
181
Hier ist jetzt der gesamte Code des Beispiels. Bitte beachten Sie, dass Sie für den FlickrAPI-Schlüssel einen eigenen Schlüssel in der Variablen apiKey spezifizieren müssen. Wie das geht, sehen Sie weiter oben. Andernfalls wird das Beispiel nicht funktionieren, und Sie bekommen keine Bilder.
Flickr / Geo Positionsbeispiel Markus Spiering / Ross Harmes / Sven Haiges
> Flickr Fotos <meta name "layout" content "webkit" /> <meta content "minimum scale 1.0, width device width, maximum scale 0.6667, user scalable no" name "viewport" /> <script type "text/javascript" src "http://maps.google.com/maps/api/js?sensor true"> <script> (function my() { var $i $i.vars
{}; {};
$i.init function() { if ($i.hasGeo) { navigator.geolocation.getCurrentPosition($i.showLocation, $i.handleError, {timeout:30000, maximumAge:300000, enableHighAccuracy:true}) } else document.getElementById('message').innerHTML 'Geolocation API nicht verfügbar!'; }; $i.showLocation function(position) { document.getElementById('message').innerHTML 'latitude: ' + position.coords.latitude + ' / longitude: ' + position.coords.longitude + ' / accuracy: ' + position.coords.accuracy + 'meters (acquired '+new Date(position.timestamp)+')'; var latlng new google.maps.LatLng(position.coords.latitude, position.coords.longitude); var myOptions { zoom: 13, center: latlng, mapTypeId: google.maps.MapTypeId.ROADMAP
182
Kapitel 2 – HTML5 in der mobilen Webentwicklung
}; $i.map
new google.maps.Map(document.getElementById("map"),
myOptions); // Fotos im Umkreis von einem Kilometer holen var apiKey 'Flickr API Schlüssel'; var requestURL 'http://api.flickr.com/services/rest/?method flickr.photos.search&api key ' + apiKey + '&media photos&lat ' + position.coords.latitude + '&lon ' + position.coords.longitude + '&radius 2&extras geo%2Curl sq&format json&jsoncallback apiCallback&per page 20'; var scriptElement document.createElement('script'); scriptElement.src requestURL; document.body.appendChild(scriptElement); } window.apiCallback var photos
function(rsp) {
rsp.photos.photo;
if (!document.getElementById('photo container')) { var photoContainer document.createElement('div'); photoContainer.id 'photo container'; document.getElementById('message').appendChild(photoContainer); } else { var photoContainer document.getElementById('photo container'); photoContainer.innerHTML ''; } var imgElement; for (var i 0, len photos.length; i < len; i++) { if (photos[i].url sq) { // Thumbnail Bild dem Container hinzufügen imgElement document.createElement('img'); imgElement.src photos[i].url sq imgElement.hspace 5 imgElement.vspace 5 imgElement.alt photos[i].title; photoContainer.appendChild(imgElement); // Markierung auf die Karte setzen new google.maps.Marker({ position: new google.maps.LatLng(photos[i].latitude, photos[i].longitude), map: $i.map, title: photos[i].title
2.5 Geolocation-API
183
}); } } }; $i.handleError { var msgNode
function(error) document.getElementById('message');
switch (error.code) { case error.TIMEOUT: msgNode.innerHTML + 'Zeit überschritten...'; navigator.geolocation.getCurrentPosition($i.showLocation, $i.handleError, {timeout:30000, maximumAge:300000}); break; case error.PERMISSION DENIED: msgNode.innerHTML + 'Benutzer hat Positionierung abgelehnt.'; break; case error.POSITION UNAVAILABLE: msgNode.innerHTML + 'Geo Position nicht verfügbar.'; break; } msgNode.innerHTML +
'
Fehlermeldung: ' + error.message;
} $i.hasGeo function() { if (navigator.geolocation) return true; else return false; }; document.addEventListener("DOMContentLoaded", $i.init, false); }).call();
Fotos in ihrer Nähe Powered by iWebKit
Dieses Beispiel hat Ihnen gezeigt, wie einfach es ist, eine Web-API anzusprechen, georeferenzierte Inhalte aus dem Netz zu holen und diese innerhalb seiner eigenen Webseite oder App zu verwenden. Stöbern Sie auch noch ein bisschen bei www.flickr.com/ services/api und schauen Sie sich die anderen georelevanten API-Methoden an.
2.5.12 Weitere georelevante API-Methoden bei Flickr Wir haben in unserem Beispiel die flickr.photos.search-API-Methode verwendet, die Geoinformationen als Eingangsparameter akzeptiert, aber noch keine der vielen »richtigen« Geo-API-Methoden bei Flickr darstellt. Über die flickr.photos.geo-Methoden können Sie beispielsweise die Geoinformationen zu beliebten Fotos abrufen oder die georeferenzierten Fotos oder Videos eines bestimmten Benutzers zu einem bestimmten Ort erhalten. Auch die flickr.places-APIMethoden bieten Ihnen Geoinformationen, aber nahezu unabhängig von Fotos, wie beispielsweise Namen von Ländern, Regionen, Landkreisen, Städtenamen und Stadtteilen. Lesezeichen http:// www.flickr.com/services/api Alle Flickr-API-Methoden finden Sie hier.
Dies ist ein weiterer Überblick über andere Anbieter, die nützliche georelevante APIs und Dienste anbieten: Anbieter
URL
Beschreibung
SimpleGEO
www.simplegeo.com
Anstatt eine Vielzahl von verschiedenen Geodiensten einzeln zu verwenden, bietet SimpleGEO bereits eine Sammlung von georeferenzierten Daten aus diversen Quellen und bereitet diese für den Einsatz in Webanwendungen und Apps vor.
Cloudmade
www.cloudmade.com
Als Alternative zur Google Maps-API kann das Angebot von Cloudmade gesehen werden. Cloudmade bietet Zugriff auf modifizierte OpenStreet-Maps mit einer Vielzahl von zusätzlichen Geoinformationen.
2.5 Geolocation-API
185
Anbieter
URL
Beschreibung
Open Street Map
www.openstreetmap.org
Das Open Street Map-Projekt ist ein Kartendienst, der, ähnlich wie Wikipedia, von Benutzern aus der ganzen Welt bearbeitet wird. Open Street Map bietet in vielen Regionen der Welt eine bessere Kartendichte als beispielsweise Google Maps oder Bing Maps. Die offene API erlaubt es Entwicklern, Informationen von Open Street Maps zu bekommen, aber auch Daten zurück in die Datenbank zu speichern.
Foursquare
www.foursquare.com/ apps
Das in New York ansässige Unternehmen bietet eine Plattform, über die Foursquare-Mitglieder in alle möglichen Orte »einchecken« können. Das Konzept ist recht spielerisch gehalten, und ein Benutzer kann immer sehen, wo seine Freunde gerade sind. Entwickler können die FoursquareAPI beispielsweise dafür nutzen, populäre Locations rund um die Position des Benutzers vorzuschlagen.
Gowalla
www.gowalla.com/api
Alles, was wir gerade über Foursquare geschrieben haben, trifft mehr oder weniger auch auf Gowalla zu. Mittels des Diensts können Benutzer ebenfalls in diverse Locations »einchecken«, dies ihrem sozialen Zirkel mitteilen und eventuell Vergünstigungen erhalten. Die Konzepte und die API sind sehr ähnlich. Gowalla bietet beispielsweise im Gegensatz zu Foursquare bereits einen Fotoservice und ist in manchen Gegenden im Großen und Ganzen populärer als seine Konkurrenz aus New York.
Yelp
www.yelp.de/developers
Yelp wurde vor nicht allzu langer Zeit in Deutschland gestartet und bietet benutzergenerierte Bewertungen von jeglichen Diensten, beispielsweise von Restaurants, Läden, Ärzten etc. Die Adressen, die Geolocation und die Bewertungen von Dienstleistungsanbietern sind über die Yelp-API abrufbar.
Yahoo! PlaceFinder
developer.yahoo.com/ geo/placefinder
Yahoo! PlaceFinder ist eine Alternative zur Google Maps-Reverse-Geocoding-API. Mit PlaceFinder können Koordinaten in Adressen und umgekehrt berechnet werden.
2.5.13 Geolocation mit jQTouch einbinden Auch wenn wir versuchen, so wenig wie möglich vorgefertigte JavaScript-Bibliotheken in unseren Beispielen zu verwenden, möchten wir Ihnen dennoch die jQTouch-Funktion jQT.updateLocation() nicht vorenthalten. Sollten Sie ohnehin planen, Ihre
186
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Webanwendung unter Nutzung von jQTouch zu erstellen, können Sie die aktuelle Position eines Benutzers mit nur wenigen Zeilen Code erhalten. Eine detaillierte Einführung zu jQTouch finden Sie am Anfang des Buchs. Die Geofunktionaliät für jQTouch ist im Verzeichnis Extensions in der Datei jqt.location.js definiert. Diese muss mit in den HTML-Code geladen werden.
>
In der Datei jqt.location.js befindet sich die Funktion updateLocation, die wir mit einer Rückruffunktion versehen. Diese JavaScript-Funktion macht letztendlich genau das Gleiche, was wir in unserem vorhergehenden Beispielen gelernt haben, und erhält die Geoposition über den navigator.geolocation.getCurrentPosition-API-Aufruf. Weiterhin setzen wir die Variable coords, um festzustellen, ob wir von dem Gerät eine Geoposition erhalten können oder nicht. Die selbst definierte Funktion setDisplay ist nur für die Textausgabe verantwortlich. Hier ist das volle Beispiel: Geo Location mit jQTouch <script type "text/javascript" src "http://www.google.com/jsapi"> <script type "text/javascript"> google.load("jqüry", "1.3.2"); <script type "text/javascript" src "jqtouch/jqtouch.js">
JavaScript Erweiterung für Geolocation einbinden <script type "application/x javascript" src "extensions/jqt.location.js">
>
<script type "text/javascript"> var jQT $.jQTouch({ }); <script type "text/javascript" charset "utf 8"> var jQT new $.jQTouch({ }); $(function(){ function setDisplay(text) { $('.info').empty().append(text) } var lookup
jQT.updateLocation(function(coords){
2.5 Geolocation-API
187
if (coords) { setDisplay('Breitengrad: ' + coords.latitude + '
Längengrad: ' + coords.longitude); } else { setDisplay('Geo Position wird nicht unterstützt.'); } }); if (lookup) { setDisplay('Aktuelle Position wird abgerufen'); } }); Geo Location
Während das Beispiel noch versucht, die Geoposition zu erhalten, und die Variable lookup den Wert true enthält, wird der Benutzer darauf hingewiesen. Wurde die Position erfolgreich bestimmt, enthalten die Variablen coords.latitude den Breitengrad und coords.latitude den Längengrad.
Bild 2.57: Nach dem Versuch, die Geoposition zu erhalten, wurde daneben die Position erfolgreich bestimmt. Breitengrad und Längengrad werden angezeigt.
2.5.14 Zusammenfassung und Ausblick Dieser Teil des Buchs hat die W3C Geolocation-API vorgestellt, die Zugriff auf die aktuelle Position des Geräts ermöglicht. Es stehen zwei Methoden zur Verfügung, über die
188
Kapitel 2 – HTML5 in der mobilen Webentwicklung
die Position des Geräts einmalig oder ständig abgefragt werden kann – getCurrentPosition und watchPosition. Eine erfolgreiche Positionsbestimmung hängt von mehreren Faktoren ab. Zunächst muss der Benutzer das notwendige Vertrauen in die Webapplikation haben und der Bestimmung durch die API zustimmen. Im nächsten Schritt müssen die Positionierungsparameter (PositionOptions), die an die oben genannten Methoden übergeben werden, passen. Es bietet sich oftmals an, zunächst eine netzwerkbasierte Methode zu benutzen (enableHighAccuracy false) und das Alter der Positionierung großzügig zu bemessen (maximumAge 600000). Falls diese Ortung glückt, kann im Hintergrund eine zweite Ortung durchgeführt werden, die dann eine höhere Genauigkeit und Aktualität hat. Die Geolocation-API ist auf aktuellen Android-basierten Geräten sowie auf Apple iPhone und iPod touch (iPhone OS 3+) gleichermaßen gut implementiert. Insofern kann die Feature-Detection ganz einfach über die Existenz des navigator. geolocation-Objekts festgestellt werden. Auch die Methoden zum Abfragen der Position, getCurrentPosition und watchPosition, sind einheitlich implementiert. Da das derzeit der Fall ist, besteht wenig Grund, ein Toolkit speziell für Geolocation einzusetzen. Dennoch gibt es bereits Geolocation-Toolkits, die beispielsweise unterschiedliche APIs abstrahieren. Im Desktop-Bereich ist Google Gears weit verbreitet und ermöglicht auch Internet Explorer-basierten Browsern den Zugriff auf Geolocation. Wenn Ihre Zielbrowser nicht nur WebKit-basiert sind, ist der Einsatz jedoch durchaus sinnvoll. An dieser Stelle sei auf das Project geo-location-javascript (http://bit.ly/ciWmAH) hingewiesen, das u. a. Plattformen wie Nokias Web Run-Time (N97 etc.), BlackBerry Devices und Browser mit Google Gears durch eine einheitliche, der Geolocation-API nachempfundene API unterstützt. Je nachdem, welche Funktionen Sie in Ihrer Webanwendung oder App planen, ist es gegebenenfalls sinnvoll, nicht die einzelnen APIs der verschiedenen Dienstanbieter aufzurufen, sondern beispielsweise auf SimpleGEO oder Cloudmade zurückzugreifen.
2.6
Web Storage
Ebenfalls ganz genau genommen nicht Teil der HTML5-Spezifikation, jedoch aktuell auf Android- und iPhone OS-basierten Geräten (und deren WebKit-basierten Browsern) verfügbar ist Web Storage. Web Storage ist eine W3C-Spezifikation und erlaubt das Speichern von beliebigen Daten bis zum Ende einer Session (Session Storage) oder darüber hinaus (Local Storage). Ganz wichtig dabei ist, dass es um die Speicherung von Daten auf Clientseite geht, ohne jegliche Serverunterstützung wie serverseitige Sessions. Zunächst scheint diese Art Speicher an Cookies zu erinnern, jedoch ist Web Storage einfacher zu benutzen, und der Speicherplatz pro »Origin« ist mit 5 MByte größer als die Menge der Daten, die mit Cookies gespeichert werden können.
2.6 Web Storage
189
Was ist ein Origin? Ein Origin ist Tupel, bestehend aus »Schema, Host, Port« (scheme/host/port). Ein Beispiel ist http://google.com. Das Schema ist hier http://, der Host google.com und der implizite Standardport 80. Das Prinzip der Origins spielt bei Web Storage eine große Rolle, wenn es um den zur Verfügung stehenden Speicherplatz sowie die Sicherheit geht. Das Storage-Limit pro Origin wird derzeit von den meisten Browsern einschließlich WebKit-basierten Browsern mit 5 MByte angegeben. Der Zugriff auf localStorage und webStorage wird ebenso per Origin bestimmt, d. h., alle Webseiten unterhalb eines Origins haben Zugriff auf den Web Storage. Durch DNS-Spoofing wird erreicht, dass ein Angreifer Zugriff auf die Daten des Web Storage bekommt. Um das zu verhindern, kann das Schema https:// eingesetzt werden, wodurch DNS-Spoofing verhindert werden kann. Web Storage sollte nicht eingesetzt werden, wenn sich mehrere Benutzer Webspeicher durch unterschiedliche Pfadnamen unterhalb eines Origins teilen. Beispielsweise kann der Benutzer von http://meinserver.de/userA auf sämtliche Daten des Benutzers unter http://meinserver.de/userB zugreifen, da der Origin in beiden Fällen http://meinserver.de ist.
2.6.1
Feature Detection: Darf Web Storage benutzt werden?
Web Storage und damit sessionStorage und localStorage stehen aktuell auf gängigen Android-basierten Geräten und auf iPhone OS zur Verfügung. Um über diese Grenzen hinaus Webseiten zu entwickeln oder einfach aus Gründen der Sicherheit, sollte jedoch per Feature Detection festgestellt werden, ob Web Storage benutzt werden kann: function hasSessionStorage() { return 'sessionStorage' in window; }; function hasLocalStorage() { return 'localStorage' in window; };
Falls Sie ohnehin schon Modernizr verwenden: if (!Modernizr.localstorage) { alert ('No localStorage!'); return; } ... if (!Modernizr.sessionstorage)
190
Kapitel 2 – HTML5 in der mobilen Webentwicklung
{ alert ('No sessionStorage!'); return; }
2.6.2
sessionStorage und localStorage
Betrachten wir zunächst den sessionStorage genauer. Die Benutzung von sessionStorage und localStorage ist analog, sie unterscheidet sich lediglich in der Dauer der Datenspeicherung. Der sessionStorage speichert alle Daten, die einer Browsersession zugehörig sind. Sobald das aktuelle Fenster oder Tab geschlossen wird, werden die damit verbundenen Daten des sessionStorage gelöscht. Pro Tab und Fenster stehen damit unabhängige Session Storages zur Verfügung, die sich gegenseitig (anders als Cookies) nicht beeinflussen. Das Storage-Interface ist wie folgt definiert. Es ist exakt das Gleiche für sessionStorage und localStorage: interface Storage { readonly attribute unsigned long length; getter DOMString key(in unsigned long index); getter any getItem(in DOMString key); setter creator void setItem(in DOMString key, in any data); deleter void removeItem(in DOMString key); void clear(); };
Beginnen wir mit der getItem()-Methode, die dazu verwendet wird, Daten zu speichern. Um unter dem Key name den Wert WebStorage abzulegen, würden wir Folgendes in JavaScript schreiben: sessionStorage.setItem('name', 'WebStorage');
Recht einfach, oder? Um später (auf der gleichen Webseite auf einer Folgeseite) auf diesen Wert erneut zuzugreifen, schreiben wir: var name
sessionStorage.getItem('name');
Anstatt der Methoden setItem()/getItem() kann auch die Kurznotation verwendet werden: sessionStorage.name 'WebStorage'; var name sessionStorage.name;
Um die Anzahl der Keys abzurufen, kann das Attribut length des Storage verwendet werden: var msg 'Wir haben ' + sessionStorage.length + ' Elemente im sessionStorage';
2.6 Web Storage
191
Dank des length-Attributs und der Methode key() können nun sehr einfach alle key/value-Paare des Storage abgerufen werden: var i, key, value; for (i 0; i < sessionStorage.length; i++) { key sessionStorage.key(i); value sessionStorage.getItem(key); existing.innerHTML + key + ' ' + value + '
'; }
existing zeigt hierbei auf ein bestehendes div-Element und wird pro Durchgang der for-Schleife um ein weiteres key/value-Paar angefüllt. Die Methode key(n) gibt also den Namen des Keys unter Position n zurück.
Um einen einzelnen Key und seinen Wert aus dem Speicher zu entfernen, wird die Methode removeItem() verwendet: sessionStorage.removeItem('name'); alert('Die neue Größe des sessionStorage ist: ' + sessionStorage.length);
Um alle Elemente des Storage zu löschen, wird die Methode clear() aufgerufen: sessionStorage.clear();
localStorage Der localStorage wird dazu verwendet, Daten über die Grenzen der aktuellen Browsersession zu speichern. Alle Daten stehen auch nach einem Neustart des Browsers oder des Systems zur Verfügung. Ebenso stehen die Daten zur Verfügung, wenn das aktuelle Fenster geschlossen wird und der gleiche Origin später wieder geöffnet wird. localStorage bietet also sogenannten persistenten Speicher. Ein möglicher Anwendungsfall ist die Speicherung von Benutzereinstellungen für eine Webapplikation oder die Implementierung eines einfachen Zählers, um die Anzahl der Besuche eines einzelnen Benutzers zu zählen – wohlgemerkt, pro Origin, nicht pro Webseite. Die Benutzung des localStorage ist identisch mit dem sessionStorage, daher erübrigt sich eine detaillierte Beschreibung. Um Daten im localStorage abzulegen und später wieder zu laden, schreiben wir also: localStorage.setItem('visits', 5); var visits localStorage.getItem('visits');
Genau so wie beim sessionStorage werden auch die Methoden removeItem(), clear(), key() und length unterstützt.
192
Kapitel 2 – HTML5 in der mobilen Webentwicklung
clear() in sessionStorage und localStorage Sowohl im sessionStorage als auch im localStorage führt clear() die gleiche Operation aus: Alle Elemente des angesprochenen Storage werden gelöscht. Im Fall des sessionStorage sind das jedoch nur die Elemente, die seit der laufenden Session im sessionStorage abgespeichert worden sind. Im Fall des localStorage kann das etwas weiter reichende Folgen haben, da damit alle Daten des localStorage eines Origins gelöscht werden. Wenn also eine Seite unter http://meinserver.de/ eine Seite per JavaScript clear() aufruft, werden auch die localStorage-Daten der Seite http://meinserver.de/andereSeite gelöscht. Arbeiten also mehrere Personen gemeinsam an einer Website, sollte der Zugriff auf den localStorage koordiniert werden. Ebenso sollte die Benutzung des localStorage generell aufgrund der 5-MByteBeschränkung und die Vergabe der Keys koordiniert werden. Wenn meinKey bereits besteht, überschreibt setItem('meinKey', 'meineDaten') damit die alten Daten.
2.6.3
Beispiele zu localStorage und sessionStorage
Um localStorage und sessionStorage weiter zu verdeutlichen, folgt jetzt dazu je ein Beispiel. Um den sessionStorage zu demonstrieren, wurden zwei Webseiten erstellt, der Benutzer kann von Seite 1 auf Seite 2 surfen. Auf der ersten Seite wird per iWebKit-UI ein Toggle erstellt, das je nach Betätigung unter sessionStorage. location true oder false speichert: Der Key location im sessionStorage wird mit false initialisiert. Die Liste der sessionStorage-Elemente zeigt lediglich dieses eine Element, nur wird der LocationSwitch auf on geschaltet, entsprechend wird location nun mit true angezeigt.
Bild 2.58: Location auf OFF und Location auf ON.
Es wird ein weiterer Wert hinzugefügt, der in der Liste erscheint. Mit dem Klick auf die nächste Seite wird die aktuelle Websession beibehalten, folglich kann auf den Wert von location zugegriffen werden.
2.6 Web Storage
193
Bild 2.59: sessionStorage 1 von 2 und sessionStorage 2 von 2.
Hier ist der Code der ersten Seite: HTML5 <meta name "layout" content "webkit" /> <style type "text/css" media "screen"> <script src "${resource(dir:'js',file:'modernizr 1.1.min.js')}" type "text/javascript"> <script> (function my() { var $i
{};
$i.init function() { if (!Modernizr.sessionstorage) { alert ('No sessionStorage!'); return } sessionStorage.location false; document.getElementById('location').addEventListener('click', function(e) { sessionStorage.location e.target.checked; $i.updateDisplay(); }, true);
194
Kapitel 2 – HTML5 in der mobilen Webentwicklung
document.getElementById('count').textContent sessionStorage.length; //add key/values document.getElementById('add').addEventListener('click', function(e){ var sKey document.getElementById('sKey').value; var sValue document.getElementById('sValue').value; sessionStorage.setItem(sKey, sValue); $i.updateDisplay(); }, true); //clear document.getElementById('clear').addEventListener('click', function(e){ sessionStorage.clear(); $i.updateDisplay(); }, true); $i.updateDisplay(); }; $i.updateDisplay var i, key;
function() {
document.getElementById('count').textContent sessionStorage.length; var existing document.getElementById('existing'); existing.textContent ''; for (i 0; i < sessionStorage.length; i++) { key sessionStorage.key(i); Value sessionStorage.getItem(key); existing.innerHTML + key + ' ' + Value + '
'; } };
document.addEventListener("DOMContentLoaded", $i.init, false); }).call();
sessionStorage [1/2]
2.6 Web Storage
195
next - <span class "name">Location
<span class "graytitle">Existing sessionStorage items (<span id "count">):
Und das ist der Code der zweiten Seite: HTML5 <meta name "layout" content "webkit" /> <style type "text/css" media "screen"> <script src "${resource(dir:'js',file:'modernizr 1.1.min.js')}" type "text/javascript"> <script> (function my() {
196
Kapitel 2 – HTML5 in der mobilen Webentwicklung
var $i
{};
$i.init function() { if (!Modernizr.sessionstorage) { alert ('No sessionStorage!'); return } document.getElementById('location').textContent sessionStorage.location; }; document.addEventListener("DOMContentLoaded", $i.init, false); }).call(); sessionStorage [2/2] back
Das Beispiel für localStorage ist ähnlich aufgebaut, verzichtet jedoch auf eine zweite Webseite. Statt eines iWebKit-UI-Toggles, um die Location an- bzw. auszuschalten, wird die Anzahl der Seitenabrufe für diesen Benutzer hochgezählt. localStorage. loadCount wird ganz einfach so initialisiert: if (!localStorage.loadCount) localStorage.loadCount 0;
Um den Zähler loadCount um 1 zu erhöhen, wird zunächst der unter loadCount gespeicherte Wert per parseInt() in eine Zahl verwandelt und dann um 1 erhöht. Das HTML-Element mit der gleichnamigen ID loadCount dient dann als Container zur Anzeige des Werts. localStorage.loadCount parseInt(localStorage.loadCount, 10) + 1; document.getElementById('loadCount').textContent localStorage.loadCount;
2.6 Web Storage
197
Wenn der Key loadCount nicht vorhanden ist, wird er mit 1 initialisiert. Die Liste zeigt entsprechend den Wert an. Die Seite wird nun zwei weitere Male geladen, wodurch loadCount je um 1 erhöht wird und somit 3 ist. Es wurden nun per JavaScript zwei weitere Key/Value-Paare hinzugefügt, die in der Liste angezeigt werden.
Bild 2.60: Beispiel einer loadCount-Operation.
Hier das vollständige Beispiel zur localStorage-Seite: HTML5 <meta name "layout" content "webkit" /> <style type "text/css" media "screen"> <script src "${resource(dir:'js',file:'modernizr 1.1.min.js')}" type "text/javascript"> <script> (function my() { var $i
{};
$i.init function() { if (!Modernizr.localstorage) { alert ('No localStorage!'); return } if (!localStorage.loadCount) localStorage.loadCount 0; localStorage.loadCount parseInt(localStorage.loadCount, 10) + 1; document.getElementById('loadCount').textContent localStorage.loadCount;
198
Kapitel 2 – HTML5 in der mobilen Webentwicklung
//add key/values document.getElementById('add').addEventListener('click', function(e){ var lKey document.getElementById('lKey').value; var lValue document.getElementById('lValue').value; localStorage.setItem(lKey, lValue); $i.updateDisplay(); }, true); //clear document.getElementById('clear').addEventListener('click', function(e){ localStorage.clear(); $i.updateDisplay(); }, true); $i.updateDisplay(); }; $i.updateDisplay var i, key;
function() {
document.getElementById('count').textContent localStorage.length; var existing document.getElementById('existing'); existing.textContent ''; for (i 0; i < localStorage.length; i++) { key localStorage.key(i); value localStorage.getItem(key); existing.innerHTML + key + ' ' + value + '
'; } };
document.addEventListener("DOMContentLoaded", $i.init, false); }).call(); localStorage - You have viewed this site <span id "loadCount">0 times.
2.6 Web Storage
199
<span class "graytitle">Existing localStorage items(<span id "count">):
2.6.4
Storage-Event
Sobald sich localStorage oder sessionStorage ändert, wird vom Browser ein Storage-Event gesendet. Dieses Event kann abgefangen werden, und so kann mit einer eigenen Logik darauf reagiert werden. Je nach Aktivität (neues Element unter Key X, Element unter X gelöscht etc.) sind unterschiedliche Attribute dieses Event-Objekts belegt. Hier zunächst das Interface des Storage-Events: interface StorageEvent : Event { readonly attribute DOMString key; readonly attribute any oldValue; readonly attribute any newValue; readonly attribute DOMString url; readonly attribute Storage storageArea; void initStorageEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString keyArg, in any oldValueArg, in any newValueArg, in DOMString urlArg, in Storage storageAreaArg); };
Die Methode initStorageEvent() kann dazu verwendet werden, ein Storage-Event zu erstellen, was normalerweise nicht notwendig ist. Falls die Webapplikation jedoch Events emulieren soll, kann es hilfreich sein.
200
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Viel wichtiger ist zunächst das Attribut storageArea, das immer gesetzt sein muss und auf den aktuell veränderten Storage zeigt: localStorage oder webStorage. Das Attribut key repräsentiert den aktuellen Key, der verändert worden ist. Sofern ein Wert unter diesem Key vorhanden war, enthält oldValue eine Kopie dieses Werts, newValue repräsentiert den neuen Wert, während url die URL des aktuellen Dokuments enthalten sollte. In unseren Tests war url jedoch sowohl auf iPhone OS 4 als auch auf Android 2.1 immer undefined. Um das Storage-Event zu empfangen, muss zunächst ein Listener registriert werden: window.addEventListener('storage', function(e){ var msgNode, msg ''; msgNode document.getElementById('message'); msg + 'StorageArea: ' + ((e.storageArea localStorage) ? "localStorage" : "sessionStorage") + '
'; msg + 'Document URL: ' + e.url + '
'; msg + 'Key: ' + e.key + '
'; msg + 'OldValue: ' + e.oldValue + '
'; msg + 'NewValue: ' + e.newValue + '
'; msgNode.innerHTML }, true);
msg;
Schauen Sie sich online das Beispiel zum Storage-Event an, um dessen Ausprägungen zu verstehen. Unter sehen Sie drei Screenshots, die dieses Beispiel zeigen. Durch Anklicken des ersten Buttons wird ein Datumsobjekt unter dem Key myKey im sessionStorage abgelegt. Das erneute Drücken überschreibt den Key myKey, somit stand ein oldValue zur Verfügung. Der Aufruf von clear() durch Anklicken von Clear all löscht alle Elemente und ist dadurch zu erkennen, dass key leer ist und oldValue und newValue null sind.
Bild 2.61: Ein Beispiel zum Storage-Event.
2.6 Web Storage
201
Hier der Code zum eben dargestellten Beispiel: HTML5 <meta name "layout" content "webkit" /> <style type "text/css" media "screen"> <script src "${resource(dir:'js',file:'modernizr 1.1.min.js')}" type "text/javascript"> <script> (function my() { var $i
{};
$i.init function() { if (!Modernizr.sessionstorage) { alert ('No sessionStorage!'); return } window.addEventListener('storage', function(e){ var msgNode, msg ''; msgNode document.getElementById('message'); msg + 'StorageArea: ' + ((e.storageArea localStorage) ? "localStorage" : "sessionStorage") + '
'; msg + 'Document URL: ' + e.url + '
'; msg + 'Key: ' + e.key + '
'; msg + 'OldValue: ' + e.oldValue + '
'; msg + 'NewValue: ' + e.newValue + '
'; msgNode.innerHTML }, true);
msg;
//add document.getElementById('add').addEventListener('click', function(e){ sessionStorage.setItem('myKey', new Date().toString()); }, true); document.getElementById('clear').addEventListener('click', function(e){ sessionStorage.clear(); }, true); };
202
Kapitel 2 – HTML5 in der mobilen Webentwicklung
document.addEventListener("DOMContentLoaded", $i.init, false); }).call(); Storage Events
2.7
Web SQL Database
Unter der Spezifikation Web SQL Database definiert das W3C eine clientseitige Datenbankschnittstelle. Genau genommen, hat die darin definierte API nichts mit HTML5 zu tun, jedoch fassen viele diese und andere Features wieder einmal unter dem Dach HTML5 zusammen. Unterstützung für diese API steht sowohl unter aktuellen AndroidGeräten als auch auf iPhone OS-basierten Geräten zur Verfügung, und deshalb darf sie an dieser Stelle natürlich nicht fehlen. Die Möglichkeit, per JavaScript auf eine im Browser definierte Schnittstelle zu einer relationalen Datenbank zugreifen zu können, ist mit Sicherheit eine der faszinierendsten APIs, die auf aktuellen mobilen Endgeräten zur Verfügung stehen. Allerdings ist dieses Thema auch ziemlich komplex, und zum Thema SQL (Structured Query Language) – der Sprache der relationalen Datenbanken – sind genügend dicke Bücher im Handel. Um Neulingen dennoch einen kurzen Überblick zu geben, beginnen wir dieses Kapitel zunächst mit der Vorstellung der wichtigsten Konzepte relationaler Datenbanken und
2.7 Web SQL Database
203
SQL-Statements, um Tabellen zu erstellen und zu löschen, um Daten in eine Datenbanktabelle einzufügen, zu verändern und zu löschen. Im nächsten Teil folgt dann die eigentliche Vorstellung der Web SQL Database-API. In unseren Tests haben wir zahlreiche Features entdeckt, die derzeit noch nicht implementiert sind. Daher beschränken wir uns auf die Vorstellung der Teile, die gut und konsistent implementiert sind. Die Vorstellung der API basiert auf einer kleinen Demoapplikation, mit der innerhalb einer einzigen HTML-Seite simple textbasierte Notizen verwaltet werden können. Den Code finden Sie weiter unten im Kapitel.
2.7.1
Grundlagen relationaler Datenbanken
Tabellen einer relationalen Datenbank enthalten die Daten in Zeilen und Spalten, ähnlich wie Excel-Worksheets. Die Zeilen stellen üblicherweise die Einträge dar, während die Spalten angeben, welche Informationen pro Eintrag gespeichert werden können. Um jeden Eintrag eindeutig identifizieren zu können, wird eine besondere Spalte als Primärschlüssel definiert, meist mit dem Namen »ID«. Eine einfache Notiztabelle könnte also so dargestellt werden: ID
Notiz
Datum
1
Meine erste Notiz ...
01.05.2010 10:00:00
2
Notiz 2
01.05.2010 10:05:00
Diese Tabelle speichert also zwei Notizen, wobei jede Notiz eine eindeutige Primärschlüssel-ID hat sowie den Text der Notiz und ein Datum, wodurch die Notizen beispielsweise nach der neuesten Notiz zuerst sortiert werden können. Um komplexere Daten zu speichern, bedienen sich relationale Datenbanken mehrerer Tabellen, die sich untereinander per Fremdschlüssel referenzieren. Ein Fremdschlüssel ist vereinfacht ausgedrückt der Primärschlüssel einer Tabelle, der jedoch innerhalb einer anderen Tabelle verwendet wird, um Daten zu referenzieren. Auf die unterschiedlichen Relationen, die durch Fremdschlüsselbeziehungen aufgebaut werden können, soll an dieser Stelle nicht eingegangen werden, da es hierzu bereits umfassende Literatur gibt.
2.7.2
SQL-Basics
Die Sprache der relationalen Datenbanken ist SQL, die Structured Query Language. SQL definiert die Syntax, um beispielsweise Tabellen in einer relationalen Datenbank anzulegen und Daten in diese Tabellen zu speichern. SQL kann grob aufgeteilt werden in Befehle, die einerseits Daten und Strukturen definieren und andererseits Daten erstellen, verändern oder löschen. Obwohl SQL ein Standard ist, gibt es je nach Datenbanksystem teils große Unterschiede und zahlreiche Erweiterungen. Zu wissen, welches Datenbanksystem genau verwendet wird, ist unerlässlich. Derzeit wird jedoch praktisch nur ein einziges Datenbanksystem von allen Browsern verwendet: SQLite22. Obwohl das aus Entwicklersicht eine erfreuliche Nachricht ist, steht die W3C-Spezifikation dadurch derzeit leider still. Das Problem besteht darin, dass sich
204
Kapitel 2 – HTML5 in der mobilen Webentwicklung
sämtliche Implementierungen für SQLite entschieden haben, wodurch die Web SQL Database-Spezifikation nicht zum Standard erhoben werden kann. Es fehlt der Nachweis, dass die so geschriebene Spezifikation nicht nur von SQLite umgesetzt werden kann. Das soll uns zunächst aber nicht kümmern. Betrachten wir nun eine kleine Auswahl aus SQL/SQLite, um grundlegende Datenbankoperationen verstehen zu können. Lesezeichen http://bit.ly/Jvnq Eine vollständige Liste aller von SQLite verstandenen Befehle finden Sie hier.
CREATE TABLE Erzeugt eine neue Datenbanktabelle. CREATE TABLE [IF NOT EXISTS] tabellen name ( spalten name spalten typ [constraints], ... );
Der Zusatz IF NOT EXISTS erzeugt die Tabelle nur, wenn es noch keine Tabelle mit exakt diesem Namen gibt. Die Spaltendefinitionen werden durch Kommata getrennt und sind nach dem Muster spalten name, spalten typ, constraints aufgebaut. constraints gibt dabei weitere Integritätsbedingungen für die aktuelle Spalte an, häufige Werte sind PRIMARY KEY (Primärschlüssel), NOT NULL (keine NULL-Werte), UNIQUE (Wert muss eindeutig in der aktuellen Spalte sein), DEFAULT (ein Standardwert wird angegeben) und AUTOINCREMENT (Wert wird automatisch erhöht).
Die Tabelle der Notizenapplikation wird durch folgendes SQL erstellt: CREATE TABLE IF NOT EXISTS notes ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, note TEXT, date DATE NOT NULL DEFAULT CURRENT TIMESTAMP );
INSERT Fügt eine neue Zeile in eine Datenbanktabelle ein. INSERT INTO tabellen name (spalte 1, ...) VALUES (wert 1, ...);
Um eine neue Notiz in der notes-Tabelle zu speichern, muss nur eine Spalte angegeben werden. Die Spalten id und date beziehen ihren Wert automatisch, da das mit CREATE TABLE so definiert wurde. Um also eine neue Notiz zu speichern, schreiben wir in SQL: INSERT INTO notes (note) VALUES ('Meine erste Notiz...');
2.7 Web SQL Database
205
SELECT Liefert als Rückgabewert eine Anzahl Zeilen aus einer Tabelle. SELECT spalte 1 [, ...] from tabelle 1 [, ...] [WHERE ausdruck] [ORDER BY spalte 1 ASC|DESC];
Die WHERE-Klausel kann dazu verwendet werden, die zurückgegebenen Spalten zu beschränken. Beispielsweise würde WHERE id > 5 nur die Zeilen zurückliefern, die einen ID-Wert höher als 5 haben. Wenn Sie alle Spalten als Rückgabe erhalten möchten, kann auch * angegeben werden. Folgende SELECT-Query liefert alle Spalten und alle Zeilen unserer notes-Tabelle, geordnet nach der Spalte date absteigend: SELECT * FROM notes ORDER BY date DESC;
UPDATE Verändert die Werte einer bestehenden Zeile. UPDATE tabellen name SET spalte 1 wert 1 [, ...] [WHERE expression];
Die neuen Werte werden dabei in der Form spalte wert angegeben und durch Kommata getrennt. Die WHERE-Klausel kann dazu benutzt werden, die Werte exakt einer Zeile und nicht aller Zeilen zu verändern. Um eine Notiz in der notes-Tabelle zu aktualisieren, schreiben wir: UPDATE notes set note 'Aktualisierte Notiz', date CURRENT TIMESTAMP WHERE id 5;
DELETE Löscht Zeilen aus einer Tabelle. DELETE FROM tabellen name [WHERE ausdruck];
Die optionale WHERE-Klausel gibt dabei an, welche Zeilen gelöscht werden sollen. Wird diese Klausel weggelassen, wird die gesamte Tabelle gelöscht: DELETE FROM notes;
Um eine einzelne Zeile zu löschen, müssen Sie das DELETE-Statement weiter eingrenzen: DELETE FROM notes WHERE id
5;
DROP TABLE Löscht eine komplette Tabelle inklusive ihrer Definition. DROP TABLE tabellen name;
Um also die notes-Tabelle komplett zu entfernen, schreiben wir: DROP TABLE notes;
Eine so gelöschte Tabelle könnte nun mit dem CREATE TABLE-Statement wieder angelegt werden.
206 2.7.3
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Transaktionen
Transaktionen sind ein wichtiger Bestandteil relationaler Datenbanken. Eine Transaktion stellt eine atomare Einheit dar und besteht aus mehreren Befehlen, die entweder alle erfolgreich ausgeführt werden können oder alle zurückgenommen werden. Transaktionen verhindern also, dass eine zusammengehörige Kette von Operationen nur halb durchgeführt wird und damit die Datenbank in einem unzulässigen und fehlerhaften Zustand hinterlässt. Die Web SQL Database-API unterstützt Transaktionen. Noch besser: Sämtliche SQL-Befehle werden immer innerhalb einer Transaktion ausgeführt.
2.7.4
Database-API
Bevor wir uns die umfangreiche Web SQL Database-API ansehen, sollten wir zunächst noch ein paar Fakten zu dieser API und den damit zusammenhängenden Datenbanken betrachten. Zunächst gilt für den Zugriff auf die Datenbanken ähnlich wie beim session- und localStorage der Web Storage-API das Origin-Prinzip. Alle Webseiten desselben Origins können also in vollem Umfang auf die Daten zugreifen, diese modifizieren und löschen. Jede Datenbank, die mit der Database-API erzeugt wird, hat einen Zugriffsnamen und eine Version. Anhand der Version kann später das Datenbankschema auf eine neuere Version migriert werden, da bestehenden Tabellen eventuell neue Spalten hinzugefügt wurden. Um eine Datenbank zu öffnen, muss immer der Name der Datenbank bekannt sein. Es gibt keine Möglichkeit, sämtliche Datenbanken eines Origins durch diese API aufzulisten oder zu löschen. Sie können zwar alle Tabellen einer Datenbank droppen. Ist die eigentliche Datenbank jedoch einmal angelegt, kann sie nicht über diese API gelöscht werden. Beginnen wir damit, die Web SQL Database-API zu erforschen. Um eine vorhandene Datenbank zu öffnen oder eine neue Datenbank entsprechenden Namens anzulegen, benutzen Sie die openDatabase-Methode, die wie nachfolgend definiert ist. (Die Web SQL-Spezifikation sieht weitere Methoden vor, beispielsweise für den synchronen Zugriff auf die Datenbanken. Diese Methoden scheinen derzeit weder auf WebKits in Android 2.1 noch bei iPhone OS 4 implementiert zu sein und werden deshalb hier nicht vorgestellt.) Database openDatabase(in DOMString name, in DOMString version, in DOMString displayName, in unsigned long estimatedSize, in optional DatabaseCallback creationCallback);
Um die notes-Datenbank zu öffnen, schreiben wir also das: var db
openDatabase('notes', '1.0', 'Offline Notes Storage', 5*1024*1024);
Hiermit öffnen oder erstellen Sie eine SQLite-Datenbank mit dem Namen notes und der Version 1.0. Der dritte Parameter gibt die Beschreibung der Datenbank an, während
2.7 Web SQL Database
207
der vierte Parameter die erwartete Größe der Datenbank darstellt. In diesem Beispiel werden 5 MByte angegeben; dadurch zeigen viele Browser keinen zusätzlichen Hinweis an, da 5 MByte die in der Spezifikation empfohlene maximale Größe der Datenbanken darstellt. Sie können mehr Speicherplatz erhalten, jedoch kann der Browser in diesem Fall dem User einen Hinweis einblenden, dem dieser erst zustimmen muss.
2.7.5
Neue Datenbank in den iPhone-Einstellungen
Die nun erstellte SQLite-Datenbank kann jetzt auf iPhone, iPod touch oder iPad unter Einstellungen/Safari/Datenbanken/notes gefunden werden. Zwar ist das interessant zu beobachten, aber für die Entwicklung ist diese Ansicht leider wenig hilfreich. Die einzigen Informationen, die Sie hier entnehmen können, sind der vorhandene und der belegte Speicherplatz. Ebenso wie jeder andere Benutzer später können Sie, falls gewünscht, die Datenbanken auch löschen.
Bild 2.62: Neue Datenbank unter iOS und unter Android.
Unter Android (2.2) haben Sie derzeit leider noch weniger Einsicht in die auf dem Gerät erstellten SQLite-Datenbanken. Sobald vom aktuellen Origin eine Datenbank erstellt wurde, können Sie lediglich über Menü/Mehr/Einstellungen/Cache löschen den gesamten Webcache inklusive aller Datenbanken löschen. Wie Ihnen sicherlich aufgefallen ist, haben wir das optionale creationCallback nicht angegeben, da es derzeit von keiner Implementierung unterstützt wird. Das creationCallback sollte eine JavaScript-Funktion darstellen, die nur dann aufgerufen wird, wenn die Datenbank soeben erstellt wurde. Es würde sich dann anbieten, in dieser Funktion das Schema der Datenbank (CREATE TABLE) durchzuführen, aber wie gesagt, dies ist leider nicht implementiert. Allerdings müssen Sie nicht umständlich erkennen, ob Tabellen in Ihrer Datenbank bereits vorhanden sind. Glücklicherweise lassen sich die CREATE TABLE-Statements mit dem Zusatz IF EXISTS versehen, wodurch eine Tabelle nur dann angelegt wird, wenn
208
Kapitel 2 – HTML5 in der mobilen Webentwicklung
sie noch nicht existiert. Somit kann mit jedem Zugriff auf die HTML-Seite der gleiche JavaScript-Code ausgeführt werden. In unserem Fall sieht die Erzeugung der notesTabelle (in der notes-Datenbank) so aus: var errorCallback function(error) { alert('errorCallBack: ' + error.code + ' / message: ' + error.message); } db.transaction(function(t){ t.executeSql('CREATE TABLE IF NOT EXISTS notes (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, note TEXT, date DATE NOT NULL DEFAULT CURRENT TIMESTAMP);'); }, errorCallback);
Um SQL im Rahmen einer Transaktion auszuführen, benutzen Sie die Methode transaction der Datenbankreferenz. Der erste Parameter stellt eine Callback-Funktion dar, an die ein Transaktionsobjekt übergeben wird (hier t). Die Methode executeSql() kann nun dazu benutzt werden, beliebiges SQL auszuführen. In unserem Fall erzeugen wir die notes-Tabelle, falls sie noch nicht existiert. Wie Sie ebenfalls sehen können, haben wir einen zweiten Parameter angegeben, der auch eine Callback-Funktion darstellt. Das errorCallback oben wird aufgerufen, sobald die Transaktion missglückt ist. In diesem Fall wird ein SQLError-Objekt an die Funktion übergeben, das zwei wichtige Attribute hat: code und message. message stellt eine (englische) Beschreibung des Fehlers dar und sollte nur während der Entwicklungszeit verwendet werden. Der folgenden Tabelle können Sie alle Fehlercodes entnehmen: Konstante
Code
Bedeutung
UNKNOWN ERROR
0
Ein unbekannter Fehler ist aufgetreten, der nicht weiter spezifiziert werden kann.
DATABASE ERR
1
Das SQL-Statement ist fehlgeschlagen, Grund kann ein fehlerhaftes Statement sein, das so von der Datenbank (SQLite) nicht verstanden wird.
VERSION ERR
2
Ein Fehler ist aufgetreten, weil die Version der Datenbank nicht der Version entsprach, die erwartet wurde.
TOO LARGE ERR
3
Die zurückgelieferte Datenmenge ist zu groß, es muss eventuell der Modifizierer LIMIT benutzt werden, um die Anzahl der Zeilen zu beschränken.
QUOTA ERR
4
Das Statement schlug fehl, da die maximale Größe der Datenbank überschritten wurde. Sofern der Benutzer nach Zustimmung zur Erhöhung der Speichermenge gefragt wurde, hat er abgelehnt.
2.7 Web SQL Database
209
Konstante
Code
Bedeutung
SYNTAX ERR
5
Das SQL-Statement schlug aufgrund der Syntax fehl, oder die Anzahl der Argumente im SQL-Statement stimmt nicht mit der Anzahl der Platzhalter überein.
COSTRAINT ERR
6
Ein SQL-Statement schlug aufgrund eines DatenbankConstraints fehl.
TIMEOUT ERR
7
Das Transaktionsobjekt konnte nicht innerhalb der vorgesehenen Zeit erzeugt werden.
Betrachten wir nochmals die transaction()-Methode der Datenbankreferenz. An diese Methode kann falls gewünscht auch ein drittes Callback übergeben werden, das im Erfolgsfall nach der Transaktion aufgerufen wird. Diese Methode kann praktisch sein, wenn Sie innerhalb der Transaktion beispielsweise neue Zeilen in eine Tabelle einfügen. Somit muss nach geglückter Transaktion oftmals die UI aktualisiert werden, was dann hier veranlasst werden kann. Die Definition der transaction()-Methode sei nun nochmals vorgestellt: void transaction(in SQLTransactionCallback callback, in optional SQLTransactionErrorCallback errorCallback, in optional SQLVoidCallback successCallback);
2.7.6
Daten speichern
Um Daten zu speichern, müssen die SQL INSERT-Statements an die Datenbank übergeben werden. Um beim Notizenbeispiel zu bleiben, müssen Sie den Text der neuen Notiz in das SQL INSERT-Statement aufnehmen: var statementSuccessCallback function(t, resultSet){ displayNotes(); //aktualisiert die UI } var statementErrorCallback function(t, error){ alert('errorCallBack: ' + error.code + ' / message: ' + error.message); } db.transaction(function(t){ t.executeSql('INSERT INTO notes (note) VALUES (?);', [newNoteText], statementSuccessCallback, statementErrorCallback); });
Rufen Sie die bereits bekannte transaction()-Methode auf und benutzen Sie die executeSql()-Methode der übergebenen Transaktion. In diesem Fall haben wir für die transaction()-Methode selbst keine Callbacks angegeben. An dieser Stelle werden die Callbacks der executeSql()-Methode benutzt, die im Gegensatz zur transaction()Methode verwirrenderweise in umgekehrter Reihenfolge angegeben werden.
210
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Die Funktion statementSuccessCallback wird also nach geglücktem Ausführen des SQL-Statements aufgerufen. Da Sie innerhalb dieser Transaktion nur ein SQL-Statement ausführen, hätten Sie genauso gut das successCallback der Transaktion benutzen können. Das statementErrorCallback wird natürlich aufgerufen, wenn das Statement nicht geglückt ist. Während beide Callbacks die aktuelle Transaktion (durch die z. B. erneut SQL ausgeführt werden kann, eventuell um einen Fehler in einer Fehlertabelle zu loggen) übergeben bekommen, wird an das statementSuccessCallback als zweiter Parameter ein SQLResultSet-Objekt übergeben, an das statementErrorCallback jedoch ein SQLError-Objekt. Das SQLResultSet-Objekt ist in obigem Beispiel nicht von Bedeutung, da wir die Datenbank nicht abgefragt haben. Im nächsten Abschnitt gehen wir jedoch darauf ein. Betrachten wir zunächst noch dieses SQL-Statement, das Ihnen sicherlich aufgefallen ist: INSERT INTO notes (note) VALUES (?);
Das ? stellt dabei einen Platzhalter dar, eine Art Makro, das später von der API aufgelöst wird. An die Stelle des ? wird ein Wert eingefügt, der in einem JavaScript-Array des zweiten Parameters an gleicher Position enthalten sein muss. In diesem Beispiel wird nur ein einziger Platzhalter benutzt, also darf das Array auch nur ein Element enthalten: var newNoteText 'Neue Notiz...'; ... t.executeSql('INSERT INTO notes (note) VALUES (?);', [newNoteText], statementSuccessCallback, statementErrorCallback);
2.7.7
SQL Injection
Um die neue Notiz in die Datenbank zu speichern, haben wir uns bewusst für ein SQLStatement mit Platzhalter (?) entschieden. Die Platzhalter werden der Reihe nach durch die Elemente eines im zweiten Parameter angegebenen Arrays ersetzt. t.executeSql('INSERT INTO notes (note) VALUES (?);', [newNoteText], ...
Im Vergleich dazu hätten wir das INSERT-Statement auch durch Zusammenfügen erstellen können: t.executeSql('INSERT INTO notes (note) VALUES (\'+newNoteText+\');', null, ...
Das birgt zweierlei Probleme: Zunächst wird das SQL-Statement durch das nun notwendige Escaping der ' relativ unleserlich. Das ließe sich noch teilweise lösen, indem für den eigentlichen String in JavaScript doppelte Anführungszeichen verwendet würden: t.executeSql("INSERT INTO notes (note) VALUES ('"+newNoteText+"');", null, ...
2.7 Web SQL Database
211
Leider gibt es aber immer noch ein gravierendes Problem. Was, wenn der Benutzer beispielsweise dies als newNoteText in eine Textbox eintippt: '); DROP TABLE notes;
Sie haben es erahnt: Durch diese Eingabe würde neben dem ersten INSERT-Statement, das hier irrelevant ist, ein zweites Stück SQL ausgeführt – in diesem Fall DROP TABLE notes;, das die gesamte notes-Tabelle löscht. Die beiden Bindestriche am Ende der Eingabe sorgen dafür, dass der restliche Text des Statements als Kommentar von SQLite ignoriert wird. Wenn die Daten, die Sie in der Datenbank speichern, nicht mit einem Server synchronisiert werden, schadet sich der Nutzer damit selbst. Das mag eventuell noch kein Problem darstellen, was aber, wenn die clientseitigen Daten synchronisiert und serverseitig weitere Operationen ausgeführt werden? Prinzipiell sollten Sie daher vom Benutzer erlangte Informationen wie Texte aus Eingabefeldern nur mithilfe von Platzhaltern in SQL-Statements einfügen. SQLite kann so die Textdaten automatisch escapen, falls notwendig.
2.7.8
Daten aktualisieren
Um bestehende Daten zu aktualisieren, müssen Sie das SQL UPDATE-Statement verwenden. Der Gebrauch unterscheidet sich im Wesentlichen nur durch das auszuführende SQL. Allerdings können wir zum ersten Mal von dem an das statementSuccessCallback übergebenen SQLResult-Objekt Gebrauch machen, wie der Kommentar andeuten soll: var statementSuccessCallback //resultSet.rowsAffected } var statementErrorCallback
function(t, resultSet){ 1
...
db.transaction(function(t){ t.executeSql('UPDATE notes set note ?, date CURRENT TIMESTAMP WHERE id ?;', [newNoteText, selected], statementSuccessCallback, statementErrorCallback); });
Innerhalb das UPDATE SQL-Statements benutzen Sie nun zwei Platzhalter. Der erste wird den aktualisierten Text der Notiz enthalten, während der zweite Platzhalter in der WHERE-Klausel des SQL-Statements benutzt wird, um eindeutig die zu aktualisierende Notiz per id zu bestimmen. Das Array, der zweite Parameter an die executeSQL()Methode, enthält nun folglich auch zwei Elemente: den neuen Text sowie die id der zu aktualisierenden Zeile in der Tabelle. Einen ersten Gebrauch können wir nun auch von dem resultSet-Objekt machen. Eines der Attribute ist rowsAffected, das die Anzahl der Tabellenzeilen zurückliefert, die verändert worden sind (das trifft also nur auf INSERT-, UPDATE- und DELETE-Statements zu).
212 2.7.9
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Datenbank-Queries
Wir haben in den vorangegangenen Beispielen bereits oft davon gesprochen, dass die UI aktualisiert wird. In diesem Beispiel bedeutet das, dass sämtliche Notizen sortiert nach Datum aus der Datenbank geholt und angezeigt werden müssen. Schauen wir uns also dieses SELECT-Statement genauer an und werfen wir auch einen Blick darauf, wie das SQLResult-Objekt die Daten unserer Abfrage enthält: var statementErrorCallback
...
db.transaction(function(t){ t.executeSql('SELECT * FROM notes ORDER BY date DESC;', null, function(transaction, resultSet){ var i, row, id, note, date; for (i { row
0; i < resultSet.rows.length; i++) resultSet.rows.item(i);
id row.id; note row.note; date row.date; //create HTML and update UI } }, statementErrorCallback); });
Zunächst wird folgendes SELECT-Statement ausgeführt, wodurch alle Zeilen der notesTabelle für unser Ergebnis selektiert werden: SELECT * FROM notes ORDER BY date DESC;
Da wir keine Platzhalter verwenden, muss auch kein zweiter Parameter mit den Ersetzungen angegeben werden. Der zweite Parameter ist also somit null. Spannend ist nun das statementSuccessCallback, da wir für das SQLResultSetObjekt zum ersten Mal die Daten unserer Abfrage erwarten können. Das SQLResultSetObjekt wird wie folgt definiert: interface SQLResultSet { readonly attribute long insertId; readonly attribute long rowsAffected; readonly attribute SQLResultSetRowList rows; }; interface SQLResultSetRowList { readonly attribute unsigned long length; getter any item(in unsigned long index); };
Das Attribut rows zeigt auf ein weiteres Objekt vom Typ SQLResultSetRowList. Dies ist das eigentliche Objekt, das unsere Daten enthält. Da das Ergebnis einer SQL-Data-
2.7 Web SQL Database
213
base zeilenorientiert ist, können wir nun jede Zeile einzeln in einer for-Schleife abfragen. Um auf die einzelnen Spalten der Zeilen zuzugreifen, kann ganz bequem die Dot-Notation verwendet werden: for (i { row
0; i < resultSet.rows.length; i++) resultSet.rows.item(i);
id row.id; note row.note; date row.date; //create HTML and update UI }
2.7.10 Daten löschen Um Daten zu löschen, bedienen wir uns des DELETE-Statements. In den meisten Fällen soll nicht die gesamte Tabelle gelöscht werden, also wird das DELETE-Statement durch eine WHERE-Klausel eingeschränkt: db.transaction(function(t){ t.executeSql('DELETE FROM notes WHERE id [selected], function(t, resultSet){ //UI aktualisieren }, statementErrorCallback); });
?',
2.7.11 Schemamigration Jede Webanwendung entwickelt sich weiter, und somit können Veränderungen des Datenbankschemas notwendig sein. Aus diesem Grund hat jede Web-SQL-Database ein version-Attribut, mit dessen Hilfe zunächst die Version der Datenbank abgefragt werden kann. Die Version ist dabei ein einfacher String, beispielsweise '1.0'. Wurde die gewünschte Version im openDatabase()-Aufruf weggelassen, wird einfach die aktuell vorhandene Version der Datenbank geöffnet (oder eine neue Datenbank zunächst angelegt). Man kann dann über das version-Attribut die Version der aktuell auf dem Endgerät vorhandenen Datenbank feststellen, und der JavaScript-Code kann bei Bedarf eine Schemamigration durchführen. var db openDatabase('notes', '', 'Offline Notes Storage', 5*1024*1024); var version db.version; //z. B. '1.0'
Folgendes Beispiel demonstriert, wie die Datenbank angelegt wird und nach Bedarf später aktualisiert werden kann. Wir machen es uns dabei zunutze, dass eine ohne Version geöffnete Datenbank, sofern sie tatsächlich noch nicht existiert, als Version
214
Kapitel 2 – HTML5 in der mobilen Webentwicklung
einen leeren String hat. Somit kann die initiale Migration auf die aktuelle Version für neue Nutzer direkt erfolgen. Für Nutzer, die bereits eine Datenbank angelegt hatten, liefert der Aufruf der openDatabase()-Methode die aktuelle Datenbank zurück, die dann mittels des version-Attributs ebenso auf Aktualität geprüft werden kann. Eine notwendige Migration wird dann analog zur Migration auf die Version 1.0 durchgeführt. Um die Version einer Datenbank zu verändern, muss die Methode changeVersion() der Datenbank benutzt werden. Diese Methode nimmt insgesamt fünf Parameter: changeVersion(alteVersion, neueVersion, migrationAlt Neu, migrationAlt Neu Fehler, migrationAlt Neu OK);
Der erste Parameter, alteVersion, stellt die aktuell vorhandene Version dar. neueVersion stellt die Version dar, die abgespeichert werden soll, wenn die Migration erfolgreich war. Das eigentliche Migrationsskript wird durch die Funktion migrationAlt Neu durchgeführt. An diese Funktion wird ein transaction-Objekt übergeben, auf dem dann executeSql('sql') wie bereits bekannt aufgerufen werden kann. Ebenso können ein Fehler-Handler sowie eine Funktion angegeben werden, die im Erfolgsfall aufgerufen wird. Folgendes Beispiel demonstriert die Integration von Datenbankmigrationen (ab der Erstellung der Datenbank): function cv 0 0 1 0(transaction) { transaction.executeSql('CREATE TABLE IF NOT EXISTS notes (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, note TEXT);'); } function cv failure 0 0 1 0(error) { alert('Fehler in Migration von 0.0 return true; }
> 1.0 conversion. ' + error.message);
function cv success 0 0 1 0() { alert('DB auf 1.0 migriert'); }
function prepareDatabase() { try { var db openDatabase('someDB', '', 'someDB Beschreibung', 5*1024*1024); if (db.version '') { //neu db, die DB muss auf die erste Version 'migriert' werden db.changeVersion("", "1.0", $i.cv 0 0 1 0, $i.cv failure 0 0 1 0, $i.cv success 0 0 1 0); }
2.7 Web SQL Database
215
else if (db.version '1.0') { alert('habe v1.0, alles OK'); //sobald sich die DB verändert, wird hier db.changeVersion aufgerufen //gleichzeitig wird die Erzeugung der DB so verändert, dass sofort die aktuellste Version erstellt wird //db.changeVersion("1.0", "2.0", $i.cv 1 0 2 0, $i.cv failure 1 0 2 0, $i.cv success 1 0 2 0); } return db; } catch(e) { alert('Konnte DB nicht öffnen/migrieren. Aktuelle Version: ' + db.version); } }
Wie immer hier das komplette Beispiel im HTML-Framework:
HTML5 SQL Datenbanken / DB Migration Markus Spiering / Sven Haiges
> DB Migration <meta name "layout" content "webkit" /> <meta content "minimum scale 1.0, width device width, maximum scale 0.6667, user scalable no" name "viewport" /> <script> (function my() { var $i
{};
$i.hasSQL function() { return typeof window.openDatabase };
"function" ? true : false;
$i.init function() { if (!$i.hasSQL()) { alert('No SQL Database, no fun!'); return; } //get current db $i.db $i.prepareDatabase();
216
Kapitel 2 – HTML5 in der mobilen Webentwicklung
} $i.errorStatementCallback function(transaction, error) { alert('errorCallBack: ' + error.code + ' / message: ' + error.message); return true; //true roll back transaction, false execution continues //transaction kann zum error loggign verwendet werden. }; $i.cv 0 0 1 0 function(transaction) { transaction.executeSql('CREATE TABLE IF NOT EXISTS notes (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, note TEXT);'); }; $i.cv failure 0 0 1 0 function(error) { alert('Fehler in Migration von 0.0 > 1.0 conversion. ' + error.message); return true; }; $i.cv success 0 0 1 0 function() { alert('DB auf 1.0 migriert'); }; $i.prepareDatabase function() { try { var db openDatabase('someDB', '', 'Migration Test', 5*1024*1024); if (db.version '') { //brand new, creating current schema and setting version db.changeVersion("", "1.0", $i.cv 0 0 1 0, $i.cv failure 0 0 1 0, $i.cv success 0 0 1 0); } else if (db.version '1.0') { alert('got v1.0, all good'); //sobald sich die DB veraendert, wird hier db.changeVersion aufgerufen //gleichzeitig wird die Erzeugung der DB so veraendert, dass sofort die aktuellste version erstellt wird //db.changeVersion("1.0", "2.0", $i.cv 1 0 2 0, $i.cv failure 1 0 2 0, $i.cv success 1 0 2 0); }
2.7 Web SQL Database
217
return db; } catch(e) { alert('Konnte DB nicht öffnen. Aktuelle Version: ' + db.version); } }; addEventListener('DOMContentLoaded', $i.init, true); }).call(); DB Migration - <span id "msg">Beim ersten Aufruf wird die DB someDB auf die Version 1.0 'migriert' und es wird das initiale Schema erstellt. Sobald sich die Anwendung ändert, kann dann analog eine Migration auf die nächste Version stattfinden.
Powered by iWebKit
Anzeige
Bedeutung Der Benutzer muss der Erstellung der Datenbank erst zustimmen.
218
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Anzeige
Bedeutung Die Datenbank wird dann erstellt und ist in den SafariEinstellungen unter Datenbanken sichtbar.
Beim ersten Aufruf wird die Datenbank someDB auf die Version 1.0 migriert, und das initiale Schema wird erstellt. Sobald sich die Anwendung ändert, kann dann analog eine Migration auf die nächste Version stattfinden.
Wird die Seite nochmals geladen, wird überprüft, ob die Version 1.0 der Datenbank immer noch verfügbar ist.
2.7.12 Web-SQL-Database: Notes-Beispielanwendung Die bisherigen Beispiele wurden recht nüchtern und ohne Web-UI präsentiert. Der Grund dafür ist der, dass für diese UI eine Menge HTML und JavaScript vonnöten ist, was die Vorstellung der API nicht vereinfacht hätte. Daher soll zum Schluss auf eine Beispielanwendung hingewiesen werden, deren Quellcode wir nun komplett vorstellen. Die bereits bekannte Notes-Notizverwaltung wird anhand der folgenden Screenshots kurz vorgestellt.
2.7 Web SQL Database
Anzeige
219
Bedeutung Der Ausgangsbildschirm. Es wurden noch keine Notizen in der Datenbank abgelegt. Die Datenbank selbst wurde durch openDatabase() zu diesem Zeitpunkt jedoch bereits erstellt.
Eine neue Notiz wird durch Anklicken des Buttons Neue Notiz ausgelöst. Der Benutzer fügt einen Text hinzu und klickt auf Speichern.
Die Notiz wurde abgespeichert. Das Datum wurde automatisch hinzugefügt. Es wurde ein SQL INSERT in die notes-Tabelle durchgeführt.
220
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Anzeige
Bedeutung Um eine Notiz zu bearbeiten oder zu löschen, kann der Benutzer auf die Notiz klicken. Der bisherige Text wird dann in der Textbox angezeigt.
Hier wurden drei Notizen angelegt ...
... die nun allesamt gelöscht werden.
Hier der Beispielcode:
HTML5 SQL Datenbanken / Notes Markus Spiering / Sven Haiges
> Notes
2.7 Web SQL Database
221
<meta name "layout" content "webkit" /> <meta content "minimum scale 1.0, width device width, maximum scale 0.6667, user scalable no" name "viewport" /> <style> .menu .delete { position: absolute; width: 70px!important; height: 30px!important; right: 10px; top: 6px; margin: 0!important; background: url("../images/delete.png") 0 0 norepeat } .hidden { display: none; } <script> (function my() { var $i
{};
$i.hasSQL function() { return typeof window.openDatabase };
"function" ? true : false;
$i.init function() { if (!$i.hasSQL()) { alert('No SQL Database, no fun!'); return; } document.getElementById('createButton'). addEventListener('click', function(e){ document.getElementById('newnoteTitle').style.display document.getElementById('newnoteForm').style.display }, true);
"block"; "block";
document.getElementById('save').addEventListener('click', function(e){ var newNoteText
document.getElementById('note').value;
if (!$i.selected) { $i.db.transaction(function(t){ t.executeSql('INSERT INTO notes (note) VALUES (?);', [newNoteText], function(t, resultSet){
222
Kapitel 2 – HTML5 in der mobilen Webentwicklung
$i.displayNotes(); }, $i.errorStatementCallback); }); } else { $i.db.transaction(function(t){ t.executeSql('UPDATE notes set note ?, date CURRENT TIMESTAMP WHERE id ?;', [newNoteText, $i.selected], function(t, resultSet){ $i.displayNotes(); $i.selected false; }, $i.errorStatementCallback); }); } //hide form, reset document.getElementById('note').value ''; document.getElementById('deleteLi').style.display "none"; document.getElementById('newnoteTitle').style.display "none"; document.getElementById('newnoteForm').style.display "none"; }, true); document.getElementById('delete').addEventListener('click', function(e){ var ok
confirm("Wirklich?");
if (!ok) return; $i.db.transaction(function(t){ t.executeSql('DELETE FROM notes WHERE id ?', [$i.selected], function(t, resultSet){ //alert(resultSet.rowsAffected); $i.displayNotes(); $i.selected false; document.getElementById('note').value ''; document.getElementById('deleteLi').style.display "none"; document.getElementById('newnoteTitle').style.display "none"; document.getElementById('newnoteForm').style.display "none"; }, $i.errorStatementCallback); }); }, true); document.getElementById('deleteAll').addEventListener('click', function(e){ var ok
confirm("Alle Notizen löschen?");
if (!ok) return;
2.7 Web SQL Database
223
$i.db.transaction(function(t){ t.executeSql('DELETE FROM notes', null, function(t, resultSet){ alert(resultSet.rowsAffected + ' Notizen geloescht.'); $i.displayNotes(); }, $i.errorStatementCallback); }); }, true); //get current db or create $i.db $i.prepareDatabase(); $i.displayNotes(); } $i.editNote function(e) { var id parseInt(e.currentTarget.id, 10); $i.db.transaction(function(t){ t.executeSql('SELECT * FROM notes WHERE id ?', [id], function(transaction, resultSet){ //alert(resultSet.rows.length); var row resultSet.rows.item(0); document.getElementById('note').value row.note; $i.selected row.id; }, $i.errorStatementCallback) }); document.getElementById('deleteLi').style.display "block"; document.getElementById('newnoteTitle').style.display "block"; document.getElementById('newnoteForm').style.display "block"; } $i.displayNotes function(){ var existingNode document.getElementById('existing'); existingNode.innerHTML ''; $i.db.transaction(function(t){ t.executeSql('SELECT * FROM notes ORDER BY date DESC;', null, function(transaction, resultSet){ var i, row, newLi, newSpan, commentSpan; //alert("got " + resultSet.rows.length + ' rows in the db'); for (i 0; i < resultSet.rows.length; i++) { row resultSet.rows.item(i); //- <span class "name">Meine erste...
newLi document.createElement('li'); newLi.setAttribute('class', 'menu note'); newLi.setAttribute('id', row.id); newSpan document.createElement('span');
224
Kapitel 2 – HTML5 in der mobilen Webentwicklung
newSpan.setAttribute('class', 'name'); newSpan.textContent row.note.substring(0,10) + '...'; newLi.appendChild(newSpan); commentSpan document.createElement('span'); commentSpan.setAttribute('class', 'comment'); commentSpan.textContent row.date; newLi.appendChild(commentSpan); newLi.addEventListener('click', $i.editNote, false); document.getElementById('existing').appendChild(newLi); } }, $i.errorStatementCallback); }/*errorCallback, successCallback*/); }; $i.errorCallback function(error) { alert('errorCallBack: ' + error.code + ' / message: ' + error.message); }; $i.errorStatementCallback function(transaction, error) { alert('errorCallBack: ' + error.code + ' / message: ' + error.message); return true; //true roll back transaction, false execution continues //transaction kann zum error loggign verwendet werden. };
$i.prepareDatabase {
function()
//migration using: /* var db openDatabase(shortName, "", displayName, maxSize); var version db.version; // For example, "1.0" */ //or try/catch try { var db openDatabase('notes', '1.0', 'Offline Notes Storage', 5*1024*1024); db.transaction(function(t){ t.executeSql('CREATE TABLE IF NOT EXISTS notes (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, note TEXT, date DATE NOT NULL DEFAULT CURRENT TIMESTAMP);'); }, $i.errorStatementCallback);
2.7 Web SQL Database
225
//if (db.changeVersion) // alert('can change version'); return db; } catch(e) { if (e 2) alert("Invalid database version."); else alert("Unknown error "+e+"."); } }; addEventListener('DOMContentLoaded', $i.init, true); }).call();
Notes <span id "msg"> <span class "graytitle">Bestehende Notizen - <span class "name">Meine erste...
<span id "newnoteTitle" style "display:none;" class "graytitle">Notiz bearbeiten
226
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Powered by iWebKit
2.7.13 Datenbanken im Safari Web Inspector und in Google Chrome Wir haben die Web Inspector-Ansicht von Safari und dem Google Chrome-Browser bereits weiter oben im Buch vorgestellt, dabei aber ausgelassen, dass nicht nur der HTML-Code einer Seite untersucht werden kann, sondern die Ansichten auch Einblicke in die Struktur von angelegten Datenbanken, Local Storage und Session Storage bieten. Um zur Datenbankansicht zu gelangen, gehen Sie einfach in das Menü Entwickler/ Developer im Safari-Browser und rufen dort Show Web Inspector auf. Als eine der Inspector-Ansichten wird anschließend Databases angeboten. Im Notes-Beispiel wurde die Datenbank notes angelegt, die sichtbar wird, wenn man die Beispielanwendung im Safari-Browser ausführt. Die Datenbank notes enthält die Felder note und date. Die Inhalte der beiden Datenfelder, also die einzelnen Datensätze, können Sie ebenfalls über den Web Inspector ansehen.
Bild 2.63: Datenbank im Safari Web Inspector.
Die gleiche Funktionalität ist auch im Google Chrome-Browser verfügbar. Dort wird der vergleichbare Web Inspector unter View/Developer/Developer Tools aufgerufen.
2.8 Offline Web Applications
227
Bild 2.64: Datenbank im Google Chrome-Web Inspector.
2.8
Offline Web Applications
Ein sehr spannendes Feature der HTML5-Spezifikation nennt sich »Offline Web Applications«. Kurz bedeutet das, dass eine beliebige HTML5-Webseite inklusive aller Ressourcen (wie Bilder, Medien), JavaScript und CSS komplett auf dem Client dauerhaft gecacht werden kann und dadurch die Webseite komplett offline verfügbar wird. Beim ersten Aufruf der Webseite lädt der Browser im Hintergrund alle in einem sogenannten Manifest-File aufgeführten Dateien herunter. Beim nächsten Aufruf der Webseite wird dann, falls eine Internetverbindung vorhanden ist, dieses Manifest kurz auf Änderungen überprüft. Falls Änderungen vorhanden sind, wird die gecachte Version angezeigt, jedoch werden im Hintergrund bereits die neuen Dateien heruntergeladen. Wenn keine Änderungen vorhanden sind oder der Browser offline ist, wird einfach die gecachte Version genommen. Aktuell implementiert iPhone OS diesen sogenannten »Application Cache«, auf Android 2.1 scheint die grundlegende Implementierung zwar vorhanden zu sein, jedoch funktioniert das Aktualisieren des Caches derzeit nicht. Insofern ist dieses HTML5-Feature derzeit auf Android leider nicht nutzbar. Es wird hier dennoch beschrieben, da eine vollständige und spezifikationskonforme Implementierung auf Android in nächster Zeit als wahrscheinlich gilt.
2.8.1
Grundlagen der Cache-Manifestdatei
Um die aktuelle HTML5-Webseite einschließlich der benötigten Ressourcen speichern zu können, benötigt der Browser die Information darüber, was genau diese Ressourcen sind. Die einzelnen Dateien, die lokal gespeichert werden sollen, werden in einer soge-
228
Kapitel 2 – HTML5 in der mobilen Webentwicklung
nannten Cache-Manifestdatei angegeben. Die eigentliche Webseite, die diese Datei referenziert, ist implizit immer dabei, d. h. sie muss nicht explizit im Manifest angegeben werden. Folgendes Beispiel zeigt ein einfaches Cache-Manifest: CACHE MANIFEST /js/functions.js /css/style.css /images/logo.jpg
Diese Manifestdatei muss nun auf einem Server verfügbar gemacht werden, üblicherweise im selben Verzeichnis wie auch die HTML5-Seite. Innerhalb des HTML-Tags dieser Webseite muss nun die Manifestdatei referenziert werden:
Wichtig ist hierbei, dass das Manifest demo.manifest mit dem Content-Type text/cache-manifest vom Server ausgeliefert wird. Das kann entweder dadurch erreicht werden, dass die eigentliche Manifestdatei dynamisch, etwa von einem Skript auf dem Server, erstellt wird oder ein Eintrag in die .htaccess-Datei des aktuellen Verzeichnisses des (Apache-)Webservers gemacht wird. Dieser Eintrag in die (eventuell noch zu erstellende) .htaccess-Datei sieht so aus: AddType text/cache manifest .manifest
Hiermit wird der Server angewiesen, alle Dateien mit der Endung .manifest mit dem Content-Type text/cache-manifest auszuliefern. Sobald die vom Browser geladene HTML-Seite über das manifest-Attribut eine Referenz auf eine Manifestdatei herstellt und diese Datei mit dem Content-Type text/cache-manifest ausgeliefert wird, versucht der Browser, die im Manifest aufgeführten Dateien für das nächste Aufrufen der Webseite zu speichern. Wenn diese Speicherung abgeschlossen ist und der Nutzer die Seite erneut lädt, wird die vorab gespeicherte Version verwendet. Im Hintergrund wird zusätzlich bei jedem Aufruf der Seite versucht, das Manifest auf Änderungen zu überprüfen. Das geschieht durch einen byteweisen Vergleich der Manifestdatei. Nicht das Modifikationsdatum der Datei ist also ausschlaggebend, sondern der Inhalt. Um die oben aufgeführte Manifestdatei zu verändern, könnte beispielsweise ein Kommentar hinzugefügt werden: CACHE MANIFEST #hier ein Kommentar /js/functions.js /css/style.css /images/logo.jpg
Sobald nicht alle Dateien heruntergeladen werden konnten, wird automatisch der gesamte Vorgang abgebrochen, und ein eventuell vorhandener älterer Cache bleibt der aktuelle Cache. Der Download kann also entweder komplett abgeschlossen werden, oder sämtliche Dateien werden verworfen. Wenn der Download der Dateien erfolgreich war, wird der vorhandene Cache ausgetauscht und beim nächsten Laden der Webseite automatisch verwendet. An dieser Stelle sollte aber betont werden, dass mit dem Abschluss des Down-
2.8 Offline Web Applications
229
loads der Dateien in der Manifestdatei nicht automatisch die aktuelle Webseite aktualisiert wird. Erst beim nächsten Laden dieser Seite werden die neuen Dateien verwendet.
2.8.2
Feststellen, ob der Browser online ist
Seit HTML5 kann der Zustand des Browsers durch navigator.onLine abgerufen werden. Es wird false zurückgegeben, wenn der Browser definitiv offline ist, und true, falls der Browser eine Verbindung haben könnte. Wichtig ist hierbei, dass nicht ständig im Hintergrund aktiv überprüft wird, ob der Browser online oder offline ist. Definitiv offline ist der Browser beispielsweise, wenn keine WLAN-Verbindung hergestellt werden konnte und auch kein Mobilfunknetz benutzt werden kann. Eine einfache Art, diesen Zustand herzustellen, ist, das Handy in den Flugmodus zu versetzen, wodurch alle drahtlosen Verbindungen unterbrochen werden. Es werden auch die Online- und Offline-Events in HTML5 definiert. In der Praxis scheint das jedoch weder auf dem iPhone OS noch auf Android derzeit implementiert zu sein. Sobald das der Fall ist, sollte folgender JavaScript-Code tatsächlich funktionieren: window.addEventListener("online", function() { alert('Du bist online!'); }, true); window.addEventListener("offline", function() { alert('Du bist offline!'); }, true);
2.8.3
Online-Whitelist und Fallback-Sektion
Die Manifestdatei kann laut Spezifikation aus bis zu drei Sektionen bestehen, die durch CACHE:, FALLBACK: und NETWORK: auf einer Zeile geschrieben eingeleitet werden. Die CACHE:-Sektion haben Sie bereits kennengelernt, da das die Standardsektion des CacheManifests ist. Unser obiges Beispiel könnten wir also auch expliziter so schreiben: CACHE MANIFEST #hier ein Kommentar CACHE: /js/functions.js /css/style.css /images/logo.jpg
In diesem Beispiel wurde zusätzlich noch eine Leerzeile eingefügt, die von den Browsern einfach ignoriert wird. Die NETWORK:-Sektion kann dazu verwendet werden, Dateien aktiv vom Caching auszuschließen. Es wird also immer versucht, die hier aufgeführten Dateien über das eventuell vorhandene Netzwerk zu laden: CACHE MANIFEST #hier ein Kommentar
230
Kapitel 2 – HTML5 in der mobilen Webentwicklung
CACHE: /js/functions.js /css/style.css /images/logo.jpg NETWORK: /dynamic/currentUsageChart.png
Die Datei currentUsageChart.png wird nun immer vom Browser angefragt, auch wenn keine Netzwerkverbindung zur Verfügung steht. Das hat zur Folge, dass dieses Bild eventuell nicht geladen werden kann und somit in der UI des Browsers als kaputter Link dargestellt wird. Soll das verhindert werden, kann man mit der FALLBACK:-Sektion angeben, welche (gecachte) Datei angezeigt werden soll, wenn die bevorzugte Datei nicht verfügbar ist: CACHE MANIFEST #hier ein Kommentar CACHE: /js/functions.js /css/style.css /images/logo.jpg NETWORK: /dynamic/currentUsageChart.png FALLBACK: /dynamic/currentUsageChart.png /offline/noChart.png
Sobald der Browser nun online ist, wird currentUsageChart.png benutzt. Wenn er offline ist, wird noChart.png angezeigt. Um Fallback-Dateien gleich für mehrere Einträge anzugeben, kann auch ein partieller Pfadname verwendet werden. Beispielsweise wird durch folgenden Eintrag in der Manifestdatei jede nicht verfügbare Ressource im /images-Verzeichnis durch fallback.png ersetzt: FALLBACK: /images/ offline/fallback.png
Wie wird ein Cache gelöscht? Je nach Plattform geschieht das auf unterschiedliche Art und Weise und ist natürlich gerade für die Entwicklung der Offlineapplikationen von Bedeutung. Um auf dem iPhone OS den Cache zu löschen, gehen Sie so vor: Einstellungen/Safari/Cache löschen. Auch wenn die derzeitige Implementierung auf Android noch dürftig ist, hier analog die Vorgehensweise dazu: vom WebKit-Browser und der aktuell gecachten Webseite aus Menü/Mehr/Einstellungen/Cache löschen. Sobald das erledigt ist, kann die Webseite neu geladen werden, wodurch das initiale Caching ausgelöst wird.
2.8 Offline Web Applications
2.8.4
231
Dynamische Erzeugung des Cache-Manifests
In realen Applikationen müssen meist weitaus mehr Dateien gecacht werden, als in den bisherigen Beispielen aufgeführt. Daher bietet es sich an, alle von der aktuellen Webseite benötigten Dateien in einem Verzeichnis auf dem Server zu hosten und dann das CacheManifest dynamisch auf Basis des aktuellen Verzeichnisinhalts zu erstellen. Da es eine Menge unterschiedlichster Sprachen gibt, die dazu serverseitig verwendet werden können, kann an dieser Stelle kein allgemeingültiges Beispiel gezeigt werden. Mit dem Grails-Framework, einem auf der Groovy-Skriptsprache basierendes Web-Framework, lässt sich eine dynamische Manifestdatei in wenigen Zeilen Code innerhalb einer GrailsAction erstellen: def manifest { def pathList [] new File("./web app/images").eachFile { if (!it.name.startsWith('.') && !it.directory) pathList HTML5 Offline Apps <meta name "apple mobile web app capable" content "yes"/> <meta name "apple mobile web app status bar style" content "black translucent"/> <meta content "minimum scale 1.0, width device width, maximum scale 0.6667, user scalable no" name "viewport" />
234
Kapitel 2 – HTML5 in der mobilen Webentwicklung
<script src "javascript/functions.js" type "text/javascript"> <script src "js/modernizr 1.5.js" type "text/javascript"> <script> (function my() { var $i $i.vars $i.init {
{}; {}; function()
if (!$i.hasApplicationCache()) { alert('No applicationCache!'); return; } //online offline aktuell nicht unterstützt window.addEventListener("online", function() { alert('Du bist online!'); }, true); window.addEventListener("offline", function() { alert('Du bist offline!'); }, true); document.getElementById('message').innerHTML (navigator.onLine) ? 'online' : 'offline'; var cache
window.applicationCache;
//setTimeout(function() { // cache.update(); //}, 5000); document.getElementById('message').innerHTML + cache.status;
' / status: ' +
//setTimeout(function() { // document.getElementById('message').innerHTML + status(2s): ' + cache.status; //}, 2000);
' /
var handler function(e) { var eventsNode document.getElementById('events'); eventsNode.innerHTML +
e.type + '
';
if ((e.type 'checking' || e.type 'progress') && !$i.startTimestamp) //on Android: no checking event $i.startTimestamp e.timeStamp; else if (e.type 'noupdate' || e.type 'updateready' || e.type 'cached')
2.8 Offline Web Applications
eventsNode.innerHTML + 'total time (s): ' + Math.abs((e.timeStamp $i.startTimestamp) / 1000); if (e.type 'updateready') window.applicationCache.swapCache(); } cache.addEventListener('checking', handler, false); cache.addEventListener('error', handler, false); cache.addEventListener('noupdate', handler, false); cache.addEventListener('downloading', handler, false); cache.addEventListener('progress', handler, false); cache.addEventListener('updateready', handler, false); cache.addEventListener('cached', handler, false); cache.addEventListener('obsolete', handler, false); }; $i.hasApplicationCache function() { if (Modernizr.applicationcache) return true; else return false; }; document.addEventListener("DOMContentLoaded", $i.init, false); }).call(); Offline Web App
235
236
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Betrachten wir zunächst die iWebKit-basierte UI dieser Webseite, die durch ein von dieser Seite referenziertes Cache-Manifest offline verfügbar gemacht wird. Wie Sie sich vorstellen können, müssen zahlreiche Ressourcen (JavaScript, CSS, Bilder), die im Zusammenhang mit iWebKit stehen, gecacht werden. Die beiden folgenden Screenshots zeigen die Webseite in Aktion. Beim ersten Aufruf der Webseite wird eine Manifestdatei vom Browser festgestellt, und der Download der Ressourcen wird eingeleitet. Das abschließende Event wird cached sein, da die Ressourcen zum ersten Mal heruntergeladen werden. Danach wird die Webseite erneut geladen, der Browser stellt jedoch eine unveränderte Manifestdatei fest. Dadurch wird nur noch das Event noupdate gesendet.
Bild 2.65: Der Browser stellt eine neue und in der rechten Abbildung eine unveränderte Manifestdatei fest.
Ein weiteres Szenario ist, dass eine veränderte Manifestdatei mit bereits bestehendem Cache vorliegt. In diesem Fall wird zunächst ein checking-Event, gefolgt von downloading, progress und abschließend bei geglücktem Download ein updatereadyEvent gesendet. Um diese Events in der UI sichtbar zu machen, wird folgendes JavaScript verwendet: var cache
window.applicationCache;
var handler function(e) { var eventsNode document.getElementById('events'); eventsNode.innerHTML +
e.type + '
';
if ((e.type 'checking' || e.type 'progress') && !$i.startTimestamp) //on Android: no checking event $i.startTimestamp e.timeStamp; else if (e.type 'noupdate' || e.type 'updateready' || e.type 'cached') eventsNode.innerHTML + 'total time (s): ' + Math.abs((e.timeStamp $i.startTimestamp) / 1000);
2.9 Zusammenfassung
237
if (e.type 'updateready') window.applicationCache.swapCache(); } cache.addEventListener('checking', handler, false); cache.addEventListener('error', handler, false); cache.addEventListener('noupdate', handler, false); cache.addEventListener('downloading', handler, false); cache.addEventListener('progress', handler, false); cache.addEventListener('updateready', handler, false); cache.addEventListener('cached', handler, false); cache.addEventListener('obsolete', handler, false);
Wie Sie sehen, wird jeweils die Funktion, die in der Variablen handler referenziert wird, auf die verschiedenen Events registriert. Sobald das Event gesendet wird, wird es zunächst in der über eventsNode referenzierten Node in die UI übertragen. Im nächsten Schritt wird dann versucht, die Dauer der jeweiligen Operation festzustellen, indem bei den Events checking und progress ein Zeitstempel genommen wird und bei Eintreten der abschließenden Events noupdate, updateready und cached die Differenz berechnet wird. Des Weiteren wird swapCache() aufgerufen, sobald das updatereadyEvent gesendet wird.
2.9
Zusammenfassung
Wenn Sie es bis hierher geschafft haben, haben Sie bereits das nötige Wissen, um Ihre eigenen Webanwendungen zu erstellen. Sie haben gelernt, welche Aufbauarten und Designgrundsätze es für mobile Webanwendungen gibt, wie JavaScript- und CSSFrameworks einzusetzen sind, und können nun Web Apps mit diversen HTML5-Funktionen erstellen. Folgendes können Sie jetzt: •
Benutzereingaben mit intelligenten Eingabefeldern gestalten.
•
Dynamische Grafiken und Charts mit dem canvas-Element erstellen.
•
Die aktuelle Position des Benutzers in einer Web App verwenden und Google Maps oder auch Flickr-Inhalte dazu anbieten.
•
Videos und Audiodateien richtig erstellen und innerhalb der Anwendung einsetzen.
•
Webanwendungen erstellen, die auch ohne Internetverbindung funktionieren.
•
Seiten und Web Apps erstellen, die Datenbanken nicht auf einem Server, sondern direkt auf dem mobilen Gerät anlegen.
238
Kapitel 2 – HTML5 in der mobilen Webentwicklung
Sie können jetzt Ihrer Fantasie freien Lauf lassen, indem Sie Webanwendungen entwickeln und auch veröffentlichen. Lesen Sie dazu das Kapitel zum Publizieren von Web Apps, »Webanwendungen und native Apps veröffentlichen«, am Ende des Buchs. Als Nächstes möchten wir Ihnen Wege und Technologien zeigen, wie Sie Ihr HTML-, CSS- und JavaScript-Wissen für eine native Anwendung nutzen können und wie Sie eine solche Anwendung für iOS und Android erstellen.
239
3
Native Anwendungen erstellen
Wir haben es schon mehrfach im Buch angesprochen, und die Möglichkeit ist einfach atemberaubend: Um native Anwendungen zu erstellen, brauchen Sie nicht unbedingt Objective-C oder Java zu beherrschen, sondern Sie können richtige iPhone- oder Android-Anwendungen mit dem bislang erlernten Wissen und den Webtechnologien HTML, CSS und JavaScript erstellen. Diese Anwendungen verhalten sich nicht nur wie richtige native Apps, sondern Sie können sie auch im iTunes App Store oder im Android Market verkaufen – was logischerweise nicht mit einer Webseite funktioniert. Die Technologie hat natürlich auch ihre Grenzen: Wenn es Ihr Ziel ist, superschnelle Spiele mit 3-D-Grafik zu programmieren, sollten Sie sich lieber schnell ein Objective-Coder C++-Buch besorgen. Hochperfomante Spiele und Programme, die sehr komplexe und schnell wechselnde Grafiken benötigen, lassen sich mit diesen Webtechnologien weniger komfortabel schreiben. Nahezu alle anderen Anwendungsgebiete sind aber durchaus möglich. Die Hilfsmittel, die zur Erstellung von nativen Anwendungen aus »Webseiten« verwendet werden, überbrücken noch ein weiteres Problem: den Zugriff auf telefontypische Funktionen wie beispielsweise die Kamera, den Sie von einem Browser aus bislang noch nicht haben. Mit den vorgestellten Frameworks haben Sie die Möglichkeit, per API auf diese Funktionen zuzugreifen und sie innerhalb Ihrer Anwendung zu benutzen.
3.1
Titanium vs. PhoneGap
Es gibt zwei primäre Anbieter von Produkten für das Vorhaben »Webtechnologien-zunativen-Anwendungen«: Titanium von Appcelerator und PhoneGap von Nitobi. Beide machen augenscheinlich das Gleiche: Sie helfen dabei, native Anwendungen aus HTML, CSS und JavaScript zu bilden, bieten Zugriff auf Gerätefunktionen, die nicht über den Browser erreichbar sind, und liefern ein Endprodukt, das eine »richtige« Anwendung ist und über den iTunes App Store oder den Android Market vertrieben werden kann. Technologisch gesehen, besteht der große Unterschied darin, dass eine native Anwendung mit PhoneGap tatsächlich immer noch eine Webanwendung ist, die in einem nativen Browserfenster läuft. Das ist vergleichbar mit einer Webanwendung, die Sie durch die richtigen Header sowie Startup-Icon und -Bildschirm auf dem Home-Bildschirm speichern können. PhoneGap generiert nativen Code für jede der unterstützten Plattformen, aber größtenteils nur für die Komponente, die die eigentliche Webanwendung anzeigt. Die
240
Kapitel 3 – Native Anwendungen erstellen
Anwendung selbst ist immer noch HTML, CSS und JavaScript mit dem Unterschied, dass PhoneGap eine Brücke zwischen den Webtechnologien und nativen Funktionen bietet. Hier liegt auch die Stärke von PhoneGap: Die gerätespezifischen APIs für den Zugriff auf beispielsweise die Geoposition oder die Bewegungssensoren sind ähnlich, wenn nicht sogar die gleichen, für eine Vielzahl der von PhoneGap unterstützten Plattformen (iOS, Android, BlackBerry). Ein weiterer Vorteil von PhoneGap ist, dass sich mit den bereits erlernten Techniken wesentlich schneller und einfacher Apps erstellen lassen, als es mit anderen Frameworks oder Technologien möglich ist. Etwas anders verhält es sich bei Titanium, das nicht nur für mobile Plattformen Anwendungen erstellen kann, sondern die gleiche Technologie für Windows, Linux und Mac OS X-Anwendungen bietet. Zahlreiche zum Teil auch größere Unternehmen verwenden die Titanium-Plattform, um ihre Desktop-Anwendungen für Windows und Apple aus einem Quellcode heraus zu erstellen. Der für uns wichtige Unterschied ist aber, dass Titanium einen Großteil des JavaScript-Codes in nativen Code umwandelt und im Gegensatz zu PhoneGap mehr nativen Code produziert. Auf einem iPhone wird beispielsweise aus dem TableView-JavaScript-Element eine native TableView-Komponente aus dem Apple UI-Kit produziert. Wie auch PhoneGap bietet Titanium die Möglichkeit, native Hardwarefunktionen und -komponenten direkt anzusprechen. Man könnte übertrieben behaupten, dass man mit PhoneGap sehr einfach und effektiv Apps erstellen kann, die wie Anwendungen aussehen und anwendungsähnliche Funktionen besitzen, aber immer noch Webseiten sind. Auch Titanium benutzt WebviewFenster, generiert aber wesentlich mehr nativen Code und produziert Anwendungen, die zu großen Teilen auch wirklich native Anwendungen sind. Das hat dann auch seinen Preis: Entwicklung mit Titanium ist sehr JavaScript-lastig, und erste Ergebnisse sind schwieriger zu realisieren als mit PhoneGap. Ein anderes Problem, das Titanium mitbringt, ist, dass jeder Bildschirm eine neue WebView-Ansicht darstellt und jeglicher JavaScript-Kontext nicht von einem Bildschirm auf den anderen übernommen wird. Das stellt in der Regel kein großes Problem für die meisten Anwendungen dar, jedoch werden Sie insbesondere bei umfangreicheren Anwendungen eine schlechtere Performance gegenüber einer nativen Objective-C-App feststellen. Wir möchten noch betonen, dass weder Titanium noch PhoneGap eine »Write once, run everywhere«-Lösung anbietet. Theoretisch können Sie einfachen Webcode schreiben und diesen mithilfe der beiden Lösungen als native Anwendung für iPhone, iPad, Android und, sofern Sie PhoneGap benutzen, auch für BlackBerry, Palm, Symbian und Windows Mobile konvertieren. In der Praxis besitzt aber jede dieser Plattformen andere Oberflächen, sehr oft auch verschiedene API-Aufrufe für die nativen Hardwarefunktionen und andere Bedienkonzepte. Selbst mit Titanium oder PhoneGap empfehlen wir Ihnen, beispielsweise für eine iPhone- und eine Android-Anwendung unterschiedliche Codegrundlagen zu verwenden. In diesem Kapitel dreht es sich hauptsächlich um PhoneGap. PhoneGap ist näher dran am Thema dieses Buchs, deckt die wichtigsten mobilen Plattformen ab und erlaubt einen leichteren Einstieg als Titanium. Falls Sie sich für die Entwicklung mit Titanium interessieren, empfehlen wir Ihnen, die Quick-Start-Tutorials auf der Titanium-Webseite durchzuarbeiten. Diese zeigen Ihnen, wie Sie schnell eine einfache Titanium-
3.2 SDKs, IDEs und ADTs
241
Hello World-Anwendung erstellen. Sie werden aber schon anhand eines einfachen Beispiels sehen, dass beide Technologien unterschiedliche Ansätze verfolgen – ein einfaches Hello World!
wie bei PhoneGap funktioniert dort nicht ohne JavaScript. Ebenfalls ein für uns wichtiger Ansatz ist, dass Sie bei einer Entwicklung mit PhoneGap eine mobile Seite entwickeln und diese in eine App transformieren. Bei Titanium entwickeln Sie spezifisch eine App mit Webtechnologien, aber Sie entwickeln eine Anwendung, die sich nicht als Webseite nutzen lässt. Das ist der große Vorteil von PhoneGap: Egal, ob Sie eine App in einem App Store haben und egal, ob sie erfolgreich ist oder nicht: Sie werden auf jeden Fall eine mobile Webanwendung besitzen, die auf mehr als nur einer Plattform läuft.
3.2
SDKs, IDEs und ADTs
Bevor Sie sich an die native App-Entwicklung wagen können, muss zuerst der Computer mit der nötigen Software und den einzelnen SDKs (Software Development Kits) ausgestattet werden. Die Unterschiede sind immens: Die Entwicklungsumgebung für iOS ist schnell installiert, aber wenn Sie alle Funktionen nutzen wollen, nicht kostenlos. Android ist kostenlos, bedarf aber vieler Schritte, bis die Entwicklungsumgebung für PhoneGap und Titanium schließlich einsatzbereit ist.
3.2.1
Entwicklungsumgebung für iOS-Entwicklung einrichten
Wenn Sie Anwendungen für die iOS-Plattform, also für iPhone, iPod touch oder iPad, erstellen möchten, benötigen Sie: •
einen Apple-Rechner mit mindestens Mac OS X 10.6.3 (Leopard),
•
das aktuelle iOS SDK mit der Xcode-Entwicklungsumgebung.
Das iOS SDK erhalten Sie bei Apple unter der Adresse http://developer.apple.com/iphone. Sie müssen sich vorher aber als Entwickler bei Apple registrieren. Das erledigen Sie durch den Register-Link im iPhone Dev Center. Die Registrierung ermöglicht Ihnen nicht nur den Zugriff auf iPhone-relevante Dokumentationen, sondern auch auf die Entwicklerseiten für den Safari-Browser – vieles ist dort auch für den mobilen Safari relevant – und für Mac OS X-Anwendungen
242
Kapitel 3 – Native Anwendungen erstellen
Bild 3.1: Das iPhone Dev Center bietet Zugriff auf alle Entwicklerdokumentationen und das SDK.
Um sich als Entwickler anzumelden, benötigen Sie eine Apple ID. Wenn Sie iTunesBenutzer sind, ist die Wahrscheinlichkeit schon sehr groß, dass Sie eine solche ID besitzen. Es ist die gleiche ID, mit der Sie in iTunes Musik, Filme oder Apps kaufen. Falls Sie noch keine Apple ID besitzen, kann sie während des Registrierungsprozesses beantragt werden. Nun gibt Ihnen ein kostenloses Apple Developer-Konto Zugriff auf das SDK, allerdings … •
… können Sie Ihre Anwendungen nicht im App Store veröffentlichen.
•
… können Sie nur im iOS-Simulator, aber nicht auf echten Geräten testen.
•
… haben Sie keinen Zugriff auf Betaversionen des SDK.
•
… haben Sie keinen Anspruch auf Apple-Support.
All diese Dinge gibt es natürlich, aber nicht kostenlos. Um aktiv Anwendungen im App Store zu verkaufen bzw. die Möglichkeit zu haben, auf einem richtigen Gerät zu testen, müssen Sie sich am iPhone Developer-Programm anmelden. Das können Sie als Einzelperson für derzeit 99 Dollar im Jahr oder als Firma für 299 Dollar pro Jahr tun. Wenn Sie sich als Einzelperson anmelden, haben nur Sie über Ihre Apple ID Zugriff auf die Entwicklerinformationen und Dokumente im iPhone Dev Center. Außerdem wird Ihr Name fest als »Verkäufer« im App Store gelistet. Sie haben keine Möglichkeit, eine Firmenbezeichnung anzugeben. Möchten Sie iOS-Anwendungen im Namen Ihrer Firma veröffentlichen oder mehreren Entwicklern Zugriff auf die Entwicklerinformationen im iPhone Dev Center geben, müssen Sie sich für einen Firmen-Account anmelden. Dieser kostet nicht nur 200 Dollar mehr im Jahr, sondern erfordert auch Belege dafür, dass Sie rechtlich in der Lage sind, im Namen der Firma am Entwicklerprogramm teilzunehmen. Für alle Anmeldungen zum iPhone Developer-Programm gilt, dass Apple generell eine Überprüfung der
3.2 SDKs, IDEs und ADTs
243
Anmeldung durchführt. Diese kann bei Einzelpersonanmeldungen ein paar Stunden dauern. Bei Firmenanmeldungen kann sich der Prozess mehrere Tage hinziehen. Teilnahme am kostenpflichtigen Apple-Entwicklerprogramm? Sie müssen für die meisten Beispiele im Buch wie auch für eigene Projekte, die Sie nicht im iTunes App Store vertreiben möchten, nicht am kostenpflichtigen AppleEntwicklerprogramm teilnehmen. Allerdings beschäftigt sich ein Teil der folgenden Beispiele mit Funktionen, die Sie nicht im Simulator testen können. Das betrifft beispielsweise den Zugriff auf die Kamera, auf die Bewegungssensoren und den Vibrationsalarm. Auch wenn viele Funktionen kostenfrei auf der Android-Plattform mit einem Android-Gerät testbar sind, gibt es immer noch API-Calls, die nur unter iOS funktionieren. Falls Sie ohnehin planen, eine iOS-Anwendung für das iPhone, das iPad oder den iPod touch zu schreiben und zu veröffentlichen, empfehlen wir Ihnen auch für die Beispiele im Buch die Teilnahme am Developer-Programm. Im iPhone Dev Center starten Sie den Download des aktuellen iOS SDK. Das fertig installierte SDK benötigt über 6 GByte Speicherplatz und sollte unbedingt im DeveloperVerzeichnis installiert werden. Dieses Verzeichnis wird als Standardverzeichnis benutzt, und Xcode erwartet, dass sich bestimmte Komponenten dort befinden.
Bild 3.2: Während der Installation werden Sie aufgefordert, die Installationskomponenten auszuwählen. Damit Sie PhoneGap verwenden können, müssen Sie auch die UNIX Development-Tools mit installieren.
3.2.2
Entwicklungsumgebung für Android-Entwicklung einrichten
Bei Android gibt es keine Anmeldung, und Google erhebt auch keine Gebühren, um Android-Anwendungen zu veröffentlichen. Allerdings ist der Installationsprozess des Android SDK nicht mit ein paar Mausklicks wie beim iOS SDK erledigt, sondern wesentlich aufwendiger. Ebenfalls im Gegensatz zur iOS-Entwicklung gibt es das Android SDK für Windows (ab Windows XP), für Mac OS (ab Version 10.5.8 und IntelMacs) sowie für Linux. Neben dem SDK benötigen Sie auch eine separate Entwicklungsumgebung – diese ist bei iOS mit Xcode bereits dabei. Android unterstützt die beliebte Eclipse-Umgebung
244
Kapitel 3 – Native Anwendungen erstellen
(http://www.eclipse.org/downloads), weiterhin JDK (Java Development Kit) 5 oder JDK 6 – wenn Sie nicht mit einem Mac arbeiten – und Oracle (http://www.oracle.com/ technetwork/java/javase/downloads) oder Apache Ant (http://ant.apache.org). Gegebenenfalls ist eine JDK-Version auf Ihrem Rechner bereits installiert. Apple liefert Mac OS X mit einer eigenen Java-Version aus. Mac-Benutzer müssen daher kein JDKPaket und auch für die Arbeit mit PhoneGap kein Apache Ant installieren. Für Windows-Benutzer: Bitte überprüfen Sie, ob Sie entweder die JDK-Version 5 oder 6 installiert haben. Wenn nicht oder wenn sich noch gar kein JDK auf Ihrem Computer befindet bzw. Sie unsicher sind, müssen Sie die Installation jetzt nachholen und sie von der oben genannten Oracle-Seite durchführen. Wir werden hier mit der Eclipse-Umgebung arbeiten. Die Eclipse-Downloadseite bietet viele Versionen der Umgebung an. Für die Android-Entwicklung können Sie folgende Eclipse-Versionen herunterladen und installieren: •
Eclipse IDE for Java Developers (empfohlen)
•
Eclipse IDE for Java EE Developers
•
Eclipse for RCP/Plug-in Developers
•
Eclipse Classic (ab Version 3.5.1)
Falls Sie sich entschieden haben, mit Eclipse zu arbeiten, empfehlen wir Ihnen, auch das Android Development Toolkit (ADT) für Eclipse zu installieren. Das ADT erweitert die Eclipse-Oberfläche, um komfortabel für Android entwickeln zu können. Sie können beispielsweise leichter Android-Projekte aufsetzen, die Benutzeroberfläche gestalten und auch fertige Programme für den Vertrieb vorbereiten. Das ADT muss innerhalb von Eclipse installiert werden: 1. Starten Sie Eclipse und wählen Sie aus dem Help-Menü die Option Install New Software. Im darauffolgenden Fenster klicken Sie auf Add.
Bild 3.3: Installation neuer Software für Eclipse.
3.2 SDKs, IDEs und ADTs
245
2. Geben Sie anschließend unter Name eine Bezeichnung wie beispielsweise Android Tools ein, geben Sie unter Location die Webadresse https://dl-ssl.google.com/ android/eclipse/ an und klicken Sie dann auf OK. Falls Probleme auftreten, versuchen Sie es ohne SSL und verwenden nur http:// anstatt https://. 3. Im Bereich Available Software markieren Sie das Kontrollfeld Developer Tools. So ist sichergestellt, dass sowohl die Android Development Tools als auch das Android DDMS (Dalvik Debug Monitor Service) mit installiert werden. Klicken Sie anschließend auf Next. Danach werden beide Komponenten noch einmal angezeigt. Bestätigen Sie mit Weiter.
Bild 3.4: Unter Developer Tools stellen Sie sicher, dass die zentralen Komponenten installiert werden.
4. Im letzten Schritt müssen Sie noch den Lizenzbedingungen zustimmen und dann, nachdem die einzelnen Komponenten installiert wurden, Eclipse neu starten. Jetzt haben Sie erst mal die Grundvoraussetzungen geschaffen, um das Android SDK benutzen zu können. Das »Starter Package« des SDK können Sie unter folgender Adresse herunterladen: http://developer.android.com/sdk/index.html. Das Starter Package hat seinen Namen erhalten, da es noch nicht das vollständige SDK ist. Je nachdem, wie umfangreich Ihre Erfordernisse sind, können Sie weitere SDKKomponenten aus dem Starterpaket hinzufügen. Um es zu installieren, wählen Sie einfach die für Ihr System richtige Datei aus und speichern sie auf Ihrem Computer.
246
Kapitel 3 – Native Anwendungen erstellen
Obwohl Sie den Android-SDK-Ordner überall auf Ihrem Computer speichern können, empfehlen wir, ihn in Ihr Benutzerverzeichnis auf der Festplatte zu sichern.
Bild 3.5: Wird das Android SDK in dem persönlichen Benutzerordner abgespeichert, ist es von der Konsole bzw. der Terminalanwendung leicht auffindbar.
Wie Sie im letzten Bild sehen können, befinden sich im tools-Verzeichnis des Android SDK viele kleine ausführbare UNIX-Programme wie beispielsweise adb oder android. Um diese von der Konsole aus aufrufen zu können, muss das System wissen, dass es bei Befehlseingaben auch in dieses Android SDK-Verzeichnis hineinsehen muss, wenn eingegebene Befehle erst einmal unbekannt erscheinen. Mac OS X Unter Mac OS X müssen Sie Ihren Texteditor aufrufen und im aktuellen Benutzerverzeichnis nach einer Datei namens .bash_profile schauen. Diese werden Sie nur in einem Dateiauswahlfenster sehen, wenn Sie die Option Versteckte Dateien anzeigen auswählen, da alle Systemdateien mit einem Punkt beginnen und oft von Texteditoren ausgeblendet werden. Ist diese Datei nicht vorhanden, muss sie mit folgendem Inhalt erstellt werden: export PATH ${PATH}:~/android sdk mac 86/tools/
Auch wenn die Datei bereits vorhanden ist, müssen Sie die eben genannte Zeile in die Datei einfügen und sie neu abspeichern.
Bild 3.6: Die Datei .bash-profile, in TextMate neu angelegt.
3.2 SDKs, IDEs und ADTs
247
Windows Unter Windows brauchen Sie nur mit der rechten Maustaste auf Mein Computer zu klicken und dann Eigenschaften auszuwählen. Anschließend öffnen Sie den Bereich Erweitert, klicken auf den Button Environment-Variablen und doppelklicken auf Pfad (unter Systemvariablen). Geben Sie dort den vollständigen Pfad zum tools-Verzeichnis an. Jetzt sind Sie fast fertig. Sie haben nun einen Teil des Android SDK bereits auf der Festplatte, aber die wichtigste Komponente, nämlich eine Android-Version, in der wir entwickeln, fehlt noch. 1. Starten Sie dazu Eclipse, wählen Sie aus dem Menü Eclipse den Punkt Preferences und anschließend im Einstellungsfenster Android aus. Hier können Sie angeben, in welchem Verzeichnis Sie das Android SDK gespeichert haben.
Bild 3.7: Auswahl des Verzeichnisses für das Android-SDK
2. Anschließend rufen Sie im Menü Window den Punkt Android SDK and AVD Manager auf.
Bild 3.8: Aufruf der Android-Packages im SDK and AVD Manager.
248
Kapitel 3 – Native Anwendungen erstellen
3. Klicken Sie dort auf Available Packages und wählen Sie anschließend die folgenden Komponenten aus: •
SDK Platform Android 1.6, API 4, Revision 3
•
SDK Platform Android 2.2, API 8, Revision 2
•
Google APIs by Google Inc., Android API 4, Revision 2
•
Google APIs by Google Inc., Android API 8, Revision 2
4. Klicken Sie nach der Auswahl auf Install Selected, dann im nächsten Fenster auf Accept All und auf Install. Die Komponenten werden nun heruntergeladen und installiert. Das Android SDK and AVD Manager-Fenster sollte diese Komponenten jetzt unter Installed Packages auflisten:
Bild 3.9: Alternativ können Sie auch alle Komponenten auswählen, die im Android SDK and AVD Manager angeboten werden.
Wie Sie sehen, ist die Installation recht umständlich, aber mit dem letzten Schritt haben Sie alle benötigten Komponenten für die Android-Entwicklung installiert. Als Nächstes beginnen Sie damit, das erste der nativen Frameworks zu installieren. Während die Installation von Titanium relativ einfach ist, wird Ihnen die PhoneGap-Installation für Android, aber auch für iOS, möglicherweise wieder etwas Kopfschmerzen bereiten.
3.2.3
PhoneGap installieren
Nachdem Sie die SDKs für beide Plattformen installiert haben, können Sie sich an den Download und die Installation von PhoneGap machen. Wenn Sie denken, dass die Installation des Android SDK schon anspruchsvoll war, dann warten Sie jetzt mal die PhoneGap-Installationen ab! Um die jeweils aktuelle Version von PhoneGap zu erhalten und die notwendigen Installationsskripte am sichersten auszuführen, sollten Sie sich bei GitHub anmelden. GitHub ist ein sehr beliebter Onlinedienst, der dabei hilft, Code mit passendem Versionsmanagement online zu speichern, zu tauschen und generell online verfügbar zu machen. Sobald Sie Mitglied bei GitHub sind und GitHub auf Ihrem Computer installiert haben, können Sie über die Kommandozeile aktuelle Programmpakete einfach auf Ihrem Computer installieren. Sie können sich dabei immer sicher sein, dass Sie die aktu-
3.2 SDKs, IDEs und ADTs
249
elle Version einer Anwendung aus dem Internet herunterladen. Bevor Sie GitHub installieren, ist es ratsam, sich unter www.github.com kostenlos anzumelden. Mit den folgenden Schritten installieren Sie GitHub: 1. Wenn Sie einen Mac-Rechner verwenden, können Sie die aktuelle Version von GitHub unter der Adresse http://code.google.com/p/git-osx-installer herunterladen. Auf dieser Seite müssen Sie nur auf Download the packages here klicken, dann auf der Folgeseite die für Ihr System passende Version herunterladen und das Installationsprogramm ausführen. Den Rest übernimmt GitHub automatisch. 2. Sind Sie Windows-Benutzer, ist der Prozess ähnlich einfach: Besuchen Sie die Seite http://code.google.com/p/msysgit, und wählen Sie einen der angebotenen .exe-Downloads aus der Feature Downloads-Spalte zur Installation von GitHub für Windows. Sie können während des Installationsprozesses alle Standardeinstellungen so lassen und die Dialoge immer bestätigen. 3. Um eine sichere Verbindung zwischen Ihrem Rechner und GitHub herzustellen, sollten Sie nach erfolgreicher GitHub-Installation SSH-Schlüsselpaare anlegen. Der Prozess ist für Windows und Mac OS X gleich, nur dass Sie unter Windows als Konsole nicht das normale Kommandozeilenfenster (cmd) benutzen, sondern die Bit-Bash-Konsole, die Sie über das Startmenü im GitHub-Ordner finden. Auf einem Mac können Sie die Terminalanwendung verwenden, die Sie im Order Programme/Dienstprogramme finden. 4. Wenn Sie noch nie einen SSH-Schlüssel erstellt haben, geben Sie in der Bit-BashKonsole (Windows) oder in der Terminalanwendung (Mac OS) folgende Zeile ein: ssh keygen
t rsa
C "[email protected]"
Den letzten Teil der Zeile müssen Sie natürlich durch Ihre E-Mail-Adresse ersetzen. Bei der ersten Abfrage drücken Sie einfach [Enter], bei der zweiten müssen Sie sich ein Passwort ausdenken und es dann noch einmal wiederholen.
Bild 3.10: So müsste Ihr Terminalfenster aussehen, wenn der SSH-Key erfolgreich erstellt wurde.
Anschließend wird Ihr Schlüssel erstellt, und Sie können ihn über die folgende Zeile in die Zwischenablage kopieren: cat ~/.ssh/id rsa.pub | pbcopy
250
Kapitel 3 – Native Anwendungen erstellen
5. Sobald sich der Schlüssel in der Zwischenablage befindet, rufen Sie in Ihrem Browser die Seite https://github.com/account#ssh_bucket auf, klicken dort auf Add Public Key und kopieren im anschließenden Fenster den Schlüsselinhalt aus der Zwischenablage in das Feld Key.
Bild 3.11: Der Schlüssel wird in das Feld Key kopiert, das Titelfeld kann auch freigelassen werden. GitHub füllt es dann mit der E-Mail-Adresse aus, mit der der Schlüssel im ersten Schritt generiert wurde.
6. Wenn Sie alles richtig gemacht haben, können Sie jetzt testweise eine SSH-Verbindung zu GitHub aufbauen. Geben Sie dazu in der Terminalanwendung bzw. unter Windows in der Bit Bash-Konsole folgende Zeile ein: ssh [email protected]
7. Anschließend geben Sie, wenn es Ihre erste SSH-Verbindung ist, Ihr selbst gewähltes SSH-Passwort ein. Passt es, erhalten Sie die Meldung, dass Sie erfolgreich erkannt wurden, GitHub aber keinen Shell-Zugang erlaubt:
Bild 3.12: GitHub erlaubt noch keinen Zugriff.
Da Sie sich jetzt mit der Konsole bzw. dem Terminalprogramm schon etwas warm gemacht haben, können wir als Nächstes PhoneGap für Xcode installieren. PhoneGap für die iOS-Entwicklung installieren Auch hier sind die ersten Schritte der PhoneGap-Installation für iOS nicht per Mausklick gemacht, sondern erfordern Eingaben in die Terminalkonsole. Rufen Sie die Terminalanwendung auf, und gehen Sie zu einem Verzeichnis, in dem Sie den Phone-
3.2 SDKs, IDEs und ADTs
251
Gap-Ordner installieren wollen. Wir empfehlen Ihnen, dieses Verzeichnis nicht auf den Desktop zu legen. Hier haben wir es in den Hauptordner des Benutzers gelegt. 1. Starten Sie den Kopiervorgang der neuesten PhoneGap-Software direkt von GitHub mit folgendem Befehl von der Konsole: git clone git://github.com/phonegap/phonegap iphone.git
2. Dadurch werden alle Komponenten heruntergeladen und in den Ordner phonegapiphone gespeichert. Ist dieser Vorgang beendet, navigieren Sie in den neu erstellten Ordner: cd phonegap iphone
3. Sind Sie in den neuen Ordner gewechselt, geben Sie folgende Zeile ein und drücken anschließend [Enter]: git submodule init
4. Und anschließend, gefolgt ebenfalls mit [Enter]: git submodule update
Ihr Terminalfenster müsste jetzt wie folgt aussehen:
Bild 3.13: Blick auf das Terminalfenster: Soweit ist noch alles in Ordnung.
5. Jetzt kommt der Moment der Wahrheit, und es wird sich herausstellen, ob Sie bei der Installation des iPhone SDK auch die UNIX-Komponenten mit installiert haben. Geben Sie, ebenfalls im Konsolenfenster, einfach den folgenden Begriff mit einem anschließenden [Enter] ein: make
Dieser Befehl führt nun ein Skript aus, das die Datei PhoneGapLibInstaller.pkg im Verzeichnis phonegap-iphone erstellt:
252
Kapitel 3 – Native Anwendungen erstellen
Bild 3.14: Die Datei PhoneGapLibInstaller.pkg wird erstellt
6. Stellen Sie jetzt sicher, dass Xcode nicht im Hintergrund läuft, und starten Sie dann das Installationsprogramm PhoneGapLibInstaller.pkg mit einem Doppelklick. Das Programm installiert nun unter anderem die PhoneGapLib und die PhoneGap Xcode-Vorlage (Template) im Xcode-Bereich, sodass Sie beim nächsten Start von Xcode auch ein PhoneGap-Projekt beginnen können. 7. Um zu überprüfen, ob bislang alles richtig verlief, führen Sie nach Beendigung der Installation das Programm Xcode aus. Xcode befindet sich zusammen mit den anderen iPhone-Entwicklungsprogrammen aus dem iOS SDK im Hauptverzeichnis der Festplatte (Macintosh HD) unter Developer und Applications. 8. Nach dem Programmstart werden Sie gefragt, was Sie tun möchten. Wählen Sie im Startbildschirm entweder New Xcode Project aus oder gehen Sie in das Xcode-Menü File/New Project. Sollte in dem nun erscheinenden Bildschirm auf der linken Seite unter User Templates die PhoneGap-Vorlage vorhanden sein und das Fenster ungefähr wie folgt aussehen, ist das definitiv ein gutes Zeichen und zeigt, dass die Installation erfolgreich war.
Bild 3.15: Bei erfolgreicher Installation sehen Sie ein PhoneGap-Template als auswählbare Vorlage in Xcode.
3.2 SDKs, IDEs und ADTs
253
PhoneGap für die Android-Entwicklung installieren Jetzt, da Sie bereits so gut in Übung sind, können Sie auch noch die Android-Version von PhoneGap auf Ihrem Computer installieren. Die Installation der wichtigsten Android-Komponenten – JDK, Android SDK, AndroidKomponenten, Eclipse und die Android Developer Tools (ADT) für Eclipse – haben wir bereits beschrieben. Für die Android-PhoneGap-Entwicklung benötigen WindowsBenutzer noch zwei weitere Komponenten: •
Apache Ant, das ebenfalls kostenfrei von der Adresse http://ant.apache.org heruntergeladen werden kann.
•
Ruby, das einfach mit einem Windows-Installer auf einem Windows-Rechner installiert werden kann. Der Windows-Installer ist unter http://rubyinstaller.org erhältlich.
1. Unter Mac OS X müssen die beiden Komponenten nicht zusätzlich installiert werden. Um jetzt die Android-Version zu PhoneGap zu bringen, geben Sie in der Konsole bzw. auf einem Mac im Terminalprogramm folgende Zeile ein: git clone git://github.com/phonegap/phonegap android.git
2. Stellen Sie sicher, dass Sie zuerst in das Verzeichnis navigieren, in dem Sie die Android-Version von PhoneGap installieren möchten. In unserem Beispiel nehmen Sie wieder das Hauptverzeichnis des derzeit angemeldeten Benutzers. 3. Nach der Installation wechseln Sie in das gerade erstellte Verzeichnis: cd phonegap android
Bild 3.16: So sollte Ihr Terminalfenster nach erfolgreicher Installation von PhoneGap für Android aussehen.
4. Bevor Sie ein neues Android-Projekt erstellen, müssen Sie Ruby aus der Konsole bzw. aus dem Terminal aufrufen, um eine PhoneGap.jar-Datei sowie ein einfaches Android-Eclipse-Projekt zu erstellen. Um zu testen, ob Sie alle Komponenten richtig installiert haben, bietet PhoneGap eine Beispielanwendung namens droidgap. Diese gilt es mit dem folgenden Ruby-Befehl aufzurufen und zu generieren: ruby ./droidgap ~/android sdk mac 86 test app com.spieri.testapp example/ ~/beispiel/test droid phonegap
254
Kapitel 3 – Native Anwendungen erstellen
Wenn keine Fehler aufgetreten sind, sollte Ihr Terminalfenster folgenden Inhalt anzeigen:
Bild 3.17: Die Beispielanwendung droidgap ist fertig.
5. Jedes Mal, wenn Sie ein neues PhoneGap-Android-Projekt starten, müssen Sie diesen Ruby-Befehl ausführen, um die Basiskomponenten erstellen und mit Eclipse kompilieren zu können. Hier ist die Syntax des Ruby-Befehls: ruby ./droidgap "[Pfad zum Android SDK]\" [App Name] [Paketname] "[www]" "[Zielpfad]"
Parameter
Beschreibung
./droidgap
Da hier die Beispielanwendung droidgap aus dem PhoneGapAndroid-Paket generiert wird, setzen Sie ./droidgap als Ausgangsparameter für die Quelldateien.
Pfad zum Android SDK
Hier spezifizieren Sie den Ordner, in dem Sie das Android SDK installiert bzw. hineinkopiert haben. Beachten Sie bei der Angabe des Parameters, dass Sie keine Leerzeichen im Pfad verwenden.
App-Name
Der Name Ihrer Anwendung.
Paketname
Der in der Entwicklung verwendete Paketname.
www
Pfad zum www-Ordner. Im sogenannten www-Ordner befinden sich die Quelldateien eines PhoneGap-Projekts, also die HTML-, CSS- und JavaScript-Dateien zusammen mit allen Ressourcen, die Sie einzubinden wünschen.
Zielpfad
Der Pfad, in dem Sie die Projektdateien generieren möchten. Ganz wichtig: Der Pfad darf sich nicht innerhalb des von Eclipse benutzten Workspace befinden. Zur Erinnerung: Den Workspace mussten Sie beim Start von Eclipse festlegen.
3.2 SDKs, IDEs und ADTs
255
Falls der Ruby-Befehl nicht erfolgreich ausgeführt wurde und Sie Fehlermeldungen erhalten haben, kann das unter anderem folgende Ursachen haben: 1. Überprüfen Sie, ob die Pfadvariable zum Android SDK-Ordner richtig gesetzt wurde. Sagt Ihnen der Fehler, dass der Befehl android nicht erkannt wurde, liegt das an der fehlenden Zuweisung. Sie müssen das Android SDK-Verzeichnis im Terminalfenster aufgelistet sehen, wenn Sie folgenden Befehl in der Konsole ausführen: echo android pfad.PNG echo $PATH
2. Überprüfen Sie, wie Sie den Verzeichnisnamen zum Android SDK im Ruby-Befehl angegeben haben. Er darf keine Leerzeichen enthalten. Unter Windows sollte die Verzeichnisangabe mit doppelten Anführungszeichen erfolgen: "C:/development/android/"
Wenn wir später auf die Entwicklung einer eigenen Android-Anwendung mit PhoneGap eingehen, werden wir Ihnen auch noch zeigen, welche Schritte Sie für ein eigenes Projekt durchführen müssen. Bislang geht es erst einmal darum, die Installation zu verifizieren. 1. Um die gerade erstellten Dateien als erste Android-Anwendung zu sehen, müssen Sie jetzt die Eclipse-Entwicklungsumgebung starten. Gehen Sie dort in das Menü File/New, und klicken Sie auf den Menüeintrag Project. Im darauffolgenden Fenster wählen Sie unter Android die Unterkategorie Android Project aus (siehe Bild rechts): 2. Klicken Sie auf Next und im folgenden Fenster auf die Option Create project from existing source. Neben dem Location-Texteingabefeld steuern Sie über den Browse-Button das gerade erstellte Verzeichnis an.
256
Kapitel 3 – Native Anwendungen erstellen
3. Wenn Sie die gleichen Werte wie in unserem Beispiel verwendet haben, befindet sich das Verzeichnis im Hauptverzeichnis des aktuellen Benutzers unter beispiel/test_droid_phonegap. Wählen Sie es aus, und bestätigen Sie mit Open. 4. Als Letztes müssen Sie noch eine SDKVersion als Build Target auswählen. In diesem Beispiel verwenden Sie Android 2.2. Die Warnung am oberen Fensterrand können Sie in diesem Fall ignorieren. Nach einem Klick auf Finish wird das Projekt erstellt. Nach diesem kurzen Prozess werden am unteren Rand des EclipseFensters drei Fehlermeldungen angezeigt. Auch diese können Sie großzügig ignorieren.
Bild 3.18: So sollte Ihr Eclipse-Fenster aussehen, nachdem Sie das Beispielprojekt erstellt und den kleinen Pfeil neben test_app im Package Explorer angeklickt haben.
3.2 SDKs, IDEs und ADTs
257
5. Im Package Explorer navigieren Sie nun in das Verzeichnis test_app/libs zur Datei phonegap.jar. Markieren Sie die Datei mit der rechten Maustaste, und wählen Sie aus dem Kontextmenü Build Path und den darin befindlichen Menüpunkt Add to Build Path:
Bild 3.19: Der richtige Weg zum BuildPath.
Dieser Schritt ist unbedingt notwendig, da hiermit der PhoneGap-Java-Code in den Kompilierungsprozess mit eingebunden wird. Sobald dieser Schritt durchgeführt ist, sind auch die zuerst angezeigten Fehler verschwunden. 6. Bevor das Beispiel ausgeführt werden kann, muss ein virtuelles Android-Gerät – also ein passender Simulator – eingerichtet werden. Rufen Sie dazu wieder den Android SDK and AVD Manager aus dem Help-Menü auf. Klicken Sie auf den Bereich Virtual Devices und anschließend auf New. 7. Im nächsten Fenster können Sie die Eigenschaften für ein neues, virtuelles AndroidTelefon eingeben. Wählen Sie bei Name eine griffige Bezeichnung, und geben Sie unter Target die Android-Version an, die Sie auch als Build Target bei der Anlage des Projekts gewählt haben. In diesem Beispiel war das Android 2.2 – API Level 8. Die anderen Angaben können Sie bislang noch vernachlässigen:
258
Kapitel 3 – Native Anwendungen erstellen
Bild 3.20: Die Eigenschaften des virtuellen Android-Supertelefons
8. Um das neue virtuelle Telefon zu speichern, klicken Sie einfach auf Create AVD und schließen den Android SDK and AVD Manager. 9. Klicken Sie im Package Explorer jetzt auf den obersten Eintrag, also auf den Anwendungsnamen test_app, und anschließend auf den grünen Play-Button in der oberen Werkzeugleiste. Im Dialogfenster Run As wählen Sie die Option Android Application:
Bild 3.21: Wahl des Applikationstyps
3.3 iOS-Apps mit PhoneGap entwickeln
259
Anschließend wird das neu angelegte virtuelle »Supertelefon« geladen. Der Zeitraum vom Start des Simulators bis zur fertigen Installation der Android-Anwendung kann mehrere Minuten betragen. Zum Schluss sollte folgender Bildschirm erscheinen:
Bild 3.22: Willkommensbildschirm des Supertelefons.
Sehen Sie ihn, haben Sie bislang alles richtig gemacht. Wenn Sie ein wenig mit der Beispielanwendung herumspielen, werden Sie merken, dass die Funktionen zum Accelerometer, der Geoposition und der Beep-Funktion nicht funktional sind. Das liegt aber nicht an PhoneGap oder dem Beispielprogramm, sondern daran, dass der Simulator diese Funktionen nicht wiedergeben kann.
3.3
iOS-Apps mit PhoneGap entwickeln
Die richtige Entwicklungsumgebung einzurichten, war ein hartes Stück Arbeit, und vielerorts können sich während der Installation, gerade für die Android-Entwicklung, Fehler einschleichen. Bleibt zu hoffen, dass PhoneGap in Zukunft einfacher zu bedienende Methoden findet. Dafür wird jetzt die eigentliche Entwicklungsarbeit und das Konvertieren von Webanwendungen in native Anwendungen mittels PhoneGap wieder einfacher.
3.3.1
Eine Anwendung für iOS erstellen
Eine eigene iOS-Anwendung wird durch die Anlage eines Xcode-Projekts mit einer PhoneGap-Vorlage begonnen. 1. Starten Sie dazu Xcode, gehen Sie in das Menü File und anschließend auf New Project. Im folgenden Fenster wählen Sie unter User Templates den Punkt PhoneGap aus und markieren im Hauptteil des Fensters das Symbol mit dem Namen PhoneGap-based Application.
260
Kapitel 3 – Native Anwendungen erstellen
2. Klicken Sie dann auf Choose, und geben Sie den Namen des Projektverzeichnisses an, unter dem PhoneGap die notwendigen Dateien anlegen soll:
Bild 3.23: Das neue iPhone-Projekt anlegen.
3. Da wir das schon einmal verwendete Beispiel mit dem Oldtimer-Autohaus auch gern als iPhone-Anwendung hätten, nehmen Sie im Beispiel den Verzeichnisnamen autohaus. Nachdem Sie die Auswahl mit Save bestätigt haben, fängt Xcode an, alle notwendigen Dateien in diesem neuen Verzeichnis anzulegen und weitere Unterverzeichnisse zu generieren. Das Xcode-Fenster sollte für Sie wie folgt aussehen:
Bild 3.24: Xcode legt das Applikationsgerüst für Sie an.
4. Im neu angelegten Verzeichnis finden Sie nicht nur zahlreiche iOS-spezifische Dateien, Icons und die Xcode-Projektdatei autohaus.xcodeproj, sondern auch ein Verzeichnis mit dem Namen www.
3.3 iOS-Apps mit PhoneGap entwickeln
261
Bild 3.25: In das Verzeichnis www gelangen alle Webdateien.
5. Wie bereits erwähnt, ist dies das Verzeichnis, in das all Ihre Ressourcen und Webdateien kommen. Die dort befindliche index.html ist die Datei, die zuerst beim Programmstart aufgerufen wird. Sie hat bei einer »frischen Installation« den folgenden Inhalt: <meta name "viewport" content "width default width; user scalable no" /> <meta http equiv "Content type" content "text/html; charset utf 8"> autohaus > <script type "text/javascript" charset "utf 8" src "phonegap.js"> <script type "text/javascript" charset "utf 8"> // If you want to prevent dragging, uncomment this section /* function preventBehavior(e) { e.preventDefault(); }; document.addEventListener("touchmove", preventBehavior, false); */ function onBodyLoad() {
262
Kapitel 3 – Native Anwendungen erstellen
document.addEventListener("deviceready",onDeviceReady,false); } /* When this function is called, PhoneGap has been initialized and is ready to roll */ function onDeviceReady() { // do your thing! }
Sie sehen, es handelt sich um eine ganz gewöhnliche HTML-Datei mit CSS-Verweisen und etwas JavaScript. Auf die einzelnen Befehle und Funktionen wird noch genauer eingegangen. Um aber überhaupt etwas auf dem Bildschirm zu sehen, schreiben Sie die folgende Zeile am Ende der Datei index.html zwischen die body-Tags: Ich bin eine App!
Jetzt lassen Sie uns diesen einfachen Code schon einmal in eine native Anwendung konvertieren. Zurück in Xcode, bemerken Sie wahrscheinlich, dass noch keine SDKVersion in der oberen linken Ecke ausgewählt ist und Sie dort Base SDK Missing sehen. Um die SDK-Version festzulegen, gehen Sie im Project-Menü in Xcode auf den Menüpunkt Edit Project Settings und im daraufhin sich öffnenden Fenster in den Bereich Build. Unter Architecture können Sie dort ein Base SDK festlegen:
Falls in dem oberen linken Menü noch Device aufgelistet ist, klicken Sie bitte darauf und verwenden folgende Auswahl: Simulator Debug iPhone Simulator
3.3 iOS-Apps mit PhoneGap entwickeln
263
Unter Android (2.2) haben Sie derzeit leider noch weniger Einsicht in die auf dem Gerät erstellten SQLite-Datenbanken. Sobald vom aktuellen Origin eine Datenbank erstellt wurde, können Sie lediglich über das Menü Mehr/ Einstellungen/Cache löschen den gesamten Webcache einschließlich aller Datenbanken löschen. Jetzt ist es so weit: Sie können auf Build and Run in der Mitte der Xcode-Werkzeugleiste klicken, sich zurücklehnen und nach dem Laden des iPhone-Simulators Ihre erste eigene iPhone-Anwendung bestaunen. Kurz nach dem Start des iPhone Simulators wird der folgende Bildschirm angezeigt. Dieser hat noch nichts mit unserem HTML-Code zu tun und – keine Angst – wird auch nicht bei jeder mit PhoneGap erstellten Anwendung angezeigt. Das ist, wie bei Web Apps auf dem iPhone auch, der uns bekannte Startup-Bildschirm, den wir gleich modifizieren werden. Die Zeile Ich bin eine App!, die wir der index.html noch hinzugefügt haben, ist bislang der einzige Inhalt unserer Anwendung.
Bild 3.26: Die erste eigene iPhone-Anwendung.
Schauen wir uns jetzt noch einmal den Code in der Datei index.html genauer an:
Change this if you want to allow scaling > <meta name "viewport" content "width default width; user scalable no" />
Diese Zeile sollte Ihnen bekannt vorkommen. Die meta-Angabe unterbindet, dass der Inhalt in der gesamten verfügbaren Bildschirmbreite angezeigt wird, der Benutzer ihn aber nicht vergrößern oder verkleinern kann. Für den Fall, dass Sie unterschiedliche CSS-Definitionen für das iPhone und das iPad verwenden möchten, kommen die folgenden Zeilen zum Einsatz. Beide sind bislang noch ausgeklammert, und die jeweiligen CSS-Dateien ipad.css und iphone.css sind nicht mit im Lieferumfang von PhoneGap enthalten, sondern müssen von Ihnen selbst erstellt werden.
264
Kapitel 3 – Native Anwendungen erstellen
iPad/iPhone specific css below, add after your main css > >
Die nächste JavaScript-Funktion ist besonders wichtig, wenn Sie Ihre Anwendung so gestalten möchten, dass der Benutzer den Inhalt nicht nach oben oder unten verschieben kann. In der index.html-Datei ist die Funktion auskommentiert, also nicht wirksam. Entfernt man die Kommentare, erhält man nicht nur folgenden Code, sondern auch das entsprechende Verhalten: function preventBehavior(e) { e.preventDefault(); }; document.addEventListener("touchmove", preventBehavior, false);
Ohne die preventBehavior()-Funktion kann der Benutzer mit dem Finger den in der App angezeigten Inhalt nach oben und nach unten ziehen. Das wird notwendig, wenn Sie eine Anwendung gestalten, deren Inhalt über die normale Bildschirmdimension hinausgeht.
Bild 3.27: Ohne die preventBehavior()-Funktion.
Mit der preventBehavior()-Funktion kann der Benutzer lange versuchen, den Bildschirm mit den Fingern nach oben oder unten zu bewegen, es wird ihm nicht gelingen. Bedingung für eine gute Bedienung: Alle Bildschirmelemente der Anwendung müssen in die Bildschirmdimensionen passen.
3.3 iOS-Apps mit PhoneGap entwickeln
265
Bild 3.28: Mit der preventBehavior()-Funktion.
Die restlichen JavaScript-Funktionen dienen dazu, zu überprüfen, ob PhoneGap richtig initialisiert wurde und die Anwendung ausgeführt werden kann. Wir werden jetzt damit beginnen, die Beispielwebseite vom Anfang des Buchs in das Projektverzeichnis zu kopieren und die Seite für eine native Anwendung umzuschreiben. Dazu ist es erforderlich, dass Sie alle dafür benötigten Dateien in das neue wwwVerzeichnis des autohaus-Projekts kopieren. Das Verzeichnis des ersten AutohausBeispiels, in dem Sie auch erstmalig iWebKit als Oberfläche verwendet haben, sah wie folgt aus: Bild 3.29: Kopieren Sie den gesamten Inhalt in das www-Verzeichnis Ihres PhoneGap-Projekts, inklusive der iWebKitFramework-Ordner für Grafiken, der CSSDefinitionen und JavaScript.
266
Kapitel 3 – Native Anwendungen erstellen
Bild 3.30: Die neuen Dateien werden durch eine Markierung hervorgehoben.
Jetzt geht es darum, die bestehende index.html von PhoneGap und die neue Seitendatei namens autohaus.html intelligent zu verbinden. Folgende Zeilen aus dem HeaderBereich werden in die bestehende PhoneGap-index.html-Datei übernommen:
Dieser Verweis wird die im Verzeichnis befindlichen iWebKit-Stylesheets mitladen. Da Sie diese Unterscheidung jetzt nicht benötigen, löschen Sie auch die beiden vorgegebenen CSS-Verlinkungen: >
Da wieder runde Ecken für das Startup-Bild verwendet werden sollen, können in der PhoneGap-Indexdatei nicht nur CSS-Definitionen eingeladen, sondern auch direkt im Code spezifiziert werden: <style>
3.3 iOS-Apps mit PhoneGap entwickeln
267
Allein durch die Zuweisung der iWebKit-CSS-Definitionen besitzt die neue iOSAnwendung den gestreiften Hintergrund:
Bild 3.31: iOS-Anwendung mit gestreiftem Hintergrund.
Die preventBehavior()-Funktion können Sie weiter auskommentiert lassen, da der Inhalt etwas länger als die Bildschirmlänge sein wird und der User scrollen muss. Jetzt können Sie sich an den eigentlichen Inhalt der Seite wagen und den Quellcode aus dem body-Bereich zwischen die body-Tags der PhoneGap-Indexdatei kopieren. Aus: Ich bin eine App!
wird jetzt: Oldtimer Kontakt
268
Kapitel 3 – Native Anwendungen erstellen
<span class "graytitle">Spitzen Oldtimer von VW und Porsche - <span class "name">Aktuelle Angebote<span class "arrow">
- <span class "name">Unsere VWs<span class "arrow">
- <span class "name">Unsere Porsche<span class "arrow">
- <span class "name">Reparaturen<span class "arrow">
- <span class "name">Preisrechner <span class "arrow">
<span class "graytitle">Wir importieren aus Kalifornien! Oldtimer Spiering
Beispielgasse 1, 12345 Bad Beispielstadt
Falls Sie den iPhone-Simulator noch im Hintergrund laufen haben, beenden Sie ihn jetzt, da Sie sonst mit großer Wahrscheinlichkeit eine Fehlermeldung von Xcode erhalten, sollten Sie versuchen, Ihre Veränderungen noch einmal mit Build and Run zu
3.3 iOS-Apps mit PhoneGap entwickeln
269
kompilieren und zu überprüfen. Sobald Sie aber diesen Prozess ausführen, startet der iPhone-Simulator wieder und zeigt Ihnen nachfolgende Bildschirme. Obwohl die Datei splash320x240.png für den Startup-Bildschirm mit in das www-Verzeichnis kopiert wurde, wird die Zeile
im linken Bild nicht mit in den Code übernommen, da sie auch nicht funktioniert hätte. Das Startup-Bild muss an einer anderen Stelle geändert werden. Bis dahin startet die Autohaus-Anwendung immer noch mit dem PhoneGap-Bildschirm. Im rechten Bild sehen Sie die Webseite nahezu eins zu eins als native iPhone-Anwendung, ohne auch nur eine einzige Zeile Objective-C programmiert zu haben.
Bild 3.32: Unsere vormalige WebApp als richtige iOS-Anwendung.
Startup-Bildschirm ändern Jetzt soll die Anwendung aber nicht mehr mit dem PhoneGap-Bildschirm starten, sondern einen eigenen Bildschirm verwenden. 1. Dazu müssen Sie einfach die Datei splash320x460.png in das Hauptverzeichnis des PhoneGap-Projekts verschieben, die dort befindliche Default.png löschen und unsere Datei in Default.png umbenennen. 2. Klicken Sie anschließend in Xcode auf Build and Run. Wie immer startet kurze Zeit später der Simulator mit unserer Anwendung. Aber: Unter Umständen sehen Sie noch das alte Bild. 3. Um den Build-Prozess schneller ausführen zu können, speichert Xcode bestimmte Dateien und vorkompilierte Header. Das hat zur Folge, dass die aktuell gebaute Anwendung nicht alle neuen Dateien oder Verweise enthält. Um das zu verhindern, empfiehlt es sich vor dem Bauen eines neuen Builds, in das Xcode-Menü Build zu gehen und dort Clean auszuwählen.
270
Kapitel 3 – Native Anwendungen erstellen
In der darauffolgenden Dialogbox lassen Sie die Häkchen an den Checkboxen gesetzt und klicken einfach auf Clean. Führen Sie Build and Run nochmals aus.
Bild 3.33: Wenn Sie alles richtig gemacht haben, sehen Sie jetzt das neue Startup-Bild.
4. Leider werden Sie feststellen, dass das Startup-Bild beim Ausblenden etwas wackelt. Das kommt daher, dass in diesem Beispiel die Kopfleiste mit berücksichtigt werden musste. Bei einer nativen iPhone-Anwendung brauchen Sie diese 20 Pixel nicht mit zu berücksichtigen und müssen stattdessen eine Startup-Bilddatei mit einer Dimension von 320 x 480 Bildpunkten im PNG-Format verwenden. Gönnen Sie Ihrer Bilddatei noch 20 Pixel mehr, tauschen Sie sie aus, und starten Sie den Build-Prozess noch einmal. Jetzt sollte alles wie gewünscht aussehen. Programm-Icon ändern Die gleiche Prozedur nehmen Sie vor, um das Standard-Icon von PhoneGap mit unserem Programm-Icon auszutauschen. 1. Dazu verschieben Sie wieder das Beispiel-Icon in der Datei icon58x58.png in das Hauptverzeichnis des Projekts, löschen das dort befindliche Piktogramm in der Datei icon.png und geben der Datei anschließend den Namen icon.png. 2. Zurück in Xcode, säubern Sie alles erst wieder mit Clean bzw. Clean All Targets und erstellen eine neue Version. Das Ergebnis sieht wie folgt aus:
3.3 iOS-Apps mit PhoneGap entwickeln
271
Auf einem iPhone 3G oder 3GS (links) sieht das neue Icon mit der Auflösung von 57 x 57 Bildpunkten richtig gut aus. Auf einem iPhone 4 mit seinem hochauflösenden Display (rechts) wird das 57-x-57-Icon zum Problem. Im Gegensatz zu den Apple-Logos sieht es blass und unscharf aus. 3. Sie können das selbst feststellen, da der iPhone Simulator auch den Bildschirm eines iPhone 4 simulieren kann. Bei laufendem Simulator wählen Sie einfach im Menüpunkt Hardware unter Device den Eintrag iPhone 4 aus. Icon und Startup-Bildschirm für Retina-Bildschirm anpassen Glücklicherweise können iPhone und iPod touch Systemgrafiken, also Icons und Startup-Bildschirme, auf kleinere Auflösungen herunterrechnen, sodass Sie mit den vollen iPhone 4-Retina-Elementgrößen arbeiten können. Bislang wurden die für das iPhone 4 zu kleinen Grafiken einfach hochgerechnet, was funktioniert, aber auf den neuen Geräten nicht gut aussieht. Alternativ können Sie statt des 57-x-57-Icons eine Icon-Grafik mit den Ausmaßen von 114 x 114 erstellen.
Bild 3.34: Das neue Icon mit 114 x 114 Bildpunkten.
1. Die kleinere Icon-Datei im Projekthauptverzeichnis wird einfach mit der neuen Datei mit dem gleichen Namen überschrieben. Sie erreichen dann in den unterschiedlichen Auflösungen folgendes Ergebnis: Auf einem Nicht-iPhone 4 (links) sieht das Icon auch wieder sehr gut aus. Der große Unterschied wird auf einem iPhone 4-Display sichtbar (rechts). Das Icon ist jetzt genauso scharf wie die Apple-Systemlogos.
272
Kapitel 3 – Native Anwendungen erstellen
2. Wenn Sie das Icon auf dem iPhone mit der Originaldatei vergleichen, sehen Sie, dass iOS einen halbkreisförmigen Glanz in der oberen Hälfte des Icons hinzufügt. In unserem Beispiel stört dieser Glanz aber eher, und wir können ihn mit folgender Einstellung in Xcode entfernen. Markieren Sie in der linken Groups & Files-Spalte in Xcode die Datei autohausInfo.plist im Ordner Resources. In der Hauptansicht sehen Sie jetzt eine Tabelle mit allerlei Einstellungen. Am Ende dieser Liste klicken Sie in den letzten Eintrag und anschließend auf das neben dem letzten Eintrag erscheinende Plussymbol. Das fügt dieser Einstellungsliste eine Zeile hinzu.
Bild 3.35: Glanzeffekte von den Icons entfernen.
3. Aus der Auswahlliste wählen Sie Icon already includes gloss effects aus und setzen ein Häkchen in die dann erscheinende Checkbox. Ein kurzes Clean mit anschließendem Build and Run zeigt Ihnen Ihr Icon mit den für iOS abgerundeten Ecken, jedoch ohne jeglichen zusätzlichen Glanz. Das iPad-Icon PhoneGap erstellt in jedem Projektverzeichnis auch eine Icon-Datei mit der Größe 72 x 72. Dieses Icon ist für iPad-Anwendungen reserviert, da für dieses Gerät die Standard-Icon-Größe 72 x 72 beträgt. Standardmäßig ist Ihr PhoneGap-Projekt für das iPad deaktiviert, wenn Sie die bisherigen Schritte mitverfolgt haben. Um Ihre Seite auf einem virtuellen iPad mit dem anderen Logo zu sehen, müssen Sie nur das Häkchen aus der Application requires iPhone environment-Checkbox in der Info.plist-Datei entfernen.
3.3 iOS-Apps mit PhoneGap entwickeln
273
Für den Startup-Bildschirm gilt das Gleiche wie für das Icon: Anstatt die Bildschirmdimensionen von 340 x 480 Bildpunkten zu nehmen, können Sie jetzt eine Bilddatei mit den Ausmaßen 640 x 960 Pixel verwenden.
3.3.2
Einstellungen in der Info.plist-Datei
Die gerade eben entdeckte Info.plist-Datei erlaubt projektweite Einstellungen und ermöglicht uns, die Anwendung noch weiter zu verbessern. Bundle display name Hier können Sie einen alternativen Namen für Ihre iOS-Anwendung vergeben. Standardmäßig wird der Anwendungsname genommen, den Sie beim Erstellen des Projekts angegeben haben. In unserem Fall sieht das kleingeschriebene autohaus nicht besonders gut aus, also löschen Sie den derzeitigen Inhalt des Felds und geben Autofinder ein. Application requires iPhone environment Ist dieses Feld markiert, wird Ihre Anwendung nicht auf einem iPad oder einem iPod touch laufen. Wählen Sie dieses Feld aus, legen Sie explizit fest, dass nur ein iPhone die von Ihnen generierte Anwendung ausführen kann. Obwohl das standardmäßig in PhoneGap markiert ist, ist es in den meisten Fällen wenig sinnvoll. Nur Anwendungen, die unbedingt eine Telefoniefunktion benötigen, sollten dieses Feld markiert haben. Status bar style Eine der meta-Zeilen haben Sie aus dem ursprünglichen Quellcode des Oldtimer-Beispiels nicht mit in die neue PhoneGap-index.html übernommen: <meta name "apple mobile web app status bar style" content "black"/>
Aus gutem Grund: Es hätte nämlich nicht funktioniert und keine Auswirkungen auf die Statusleiste gehabt. Anstatt ein meta-Tag im HTML-Code zu verwenden, kann diese Einstellung in der Info.plist-Datei vorgenommen werden. Die Variable Status bar style bietet folgende Auswahlmöglichkeiten: Menüauswahl
Beschreibung
Grey style (default)
Die normale iOS-Statusleiste in Grau. Sie wird auch verwendet, wenn Sie die Status bar style-Einstellung nicht angeben.
Opaque black style
Schwarze, undurchsichtige Statusleiste.
Transparent black style Schwarze Statusleiste. 50 % transparent und somit durchsichtig. (alpha of 0.5)
Status bar is initially hidden Insbesondere bei Spielen wollen Sie möglicherweise komplett auf die Statusleiste verzichten. Falls Sie ein Häkchen bei Status bar is initially hidden setzen, wird keine Statusleiste angezeigt. Diese Einstellung überschreibt auch die Einstellung Status bar style.
274
Kapitel 3 – Native Anwendungen erstellen
Bild 3.36: Links die Standardstatusleiste im klassischen iPhoneGrau. Darf’s etwas dunkler sein? In der Mitte die Statusleiste in Schwarz, beliebt und gut aussehend bei iPhone-Anwendungen mit dunklen bzw. schwarzen Hintergrundfarben.
Bild 3.37: Üblich bei Spielen: Mit der Info.plist-Einstellung Status bar is initially hidden kann die Statusleiste auch komplett ausgeblendet werden.
Supported interface orientations In den Info.plist-Einstellungen können Sie ebenfalls festlegen, ob Ihre Anwendung im Hoch- oder im Querformat laufen kann. Dabei wird in Xcode und somit auch in unseren PhoneGap-Projekten sogar zwischen iPhone/iPod touch und dem iPad unterschieden.
Bild 3.38: Die Supported interface orientations für das iPad.
Mit Supported interface orientations (iPad) legen Sie fest, in welcher Geräteausrichtung Ihre App laufen bzw. ob sie diese Ausrichtung unterstützen soll. In obigem Beispiel kann das iPad in jede der vier Richtungen gedreht werden, und die Anwendung wird sich immer dem Bildschirm anpassen. Anders bei der nächsten Einstellung: Unter Supported interface orientations werden die Einstellungen für das iPhone bzw. den iPod touch festgelegt. Würden Sie die Einstellungen so belassen, könnte die App nur im Hochformat dargestellt werden – egal ob der Home-Button oben oder unten wäre. Bei Spielen sehen Sie beispielsweise sehr oft, dass sie nur im Querformat laufen. Das können Sie erzwingen, indem Sie die Werte von Portrait (Hochformat) auf Landscape (Querformat) umstellen. Eine so eingestellte Anwendung oder ein so eingestelltes Spiel würde sich wie folgt verhalten:
3.3 iOS-Apps mit PhoneGap entwickeln
275
Bild 3.39: Die Anwendung wird vom Start weg im Querformat ausgeführt. Haben Sie in den Supported interface orientations der App keine PortraitUnterstützung, bleibt sie auch im Hochformat in der eingestellten LandscapePosition.
Initial interface orientation Wenn Ihre App das Hoch- und das Querformat eines iPhones oder iPads unterstützt, können Sie diese Einstellung dazu verwenden, dem System mitzuteilen, in welchem Modus die Anwendung zuerst starten soll. Falls Ihre App nur im Hochformat läuft und Sie das in den Supported interface orientations-Einstellungen bereits so festgelegt haben, ist die Angabe dieser Einstellung überflüssig. jQTouch-Besonderheiten Alles, was Sie bis jetzt gelernt haben, können Sie auch auf unser jQTouch-Beispiel anwenden. Auch wenn wir im Laufe des Buchs iWebKit aufgrund seines einfachen Aufbaus und seiner Kompatibilität zwischen den verschiedenen Plattformen bewusst für unsere Beispiele gewählt haben, ist es durchaus sehr sinnvoll, jQTouch für native iPhone Apps mit PhoneGap zu verwenden. Im Gegensatz zu iWebKit 5 enthält jQTouch bereits eine ganze Menge an Animationen, die von PhoneGap auch voll unterstützt werden. Unseren Beispielcode können Sie fast unverändert lassen, allerdings sollten Sie – damit unser Beispiel auch komplett offline funktioniert – die jQuery-JavaScript-Bibliothek nicht dynamisch von Google laden, sondern in die Anwendung integrieren. Dazu müssen Sie den head-Bereich des Beispiels wie folgt ändern: <meta name "layout" content "webkit" /> Oldtimer Spiering <script type "text/javascript" src "jQuery.js"> <script type "text/javascript" src "jqtouch/jqtouch.js">
276
Kapitel 3 – Native Anwendungen erstellen
var jQT $.jQTouch({ });
>
Bevor das funktioniert, muss die jQuery.js von der Seite http://jquery.com heruntergeladen und im Verzeichnis der index.html-Datei im www-Verzeichnis des PhoneGap-Projekts gespeichert werden. Wenn Sie jQuery nicht lokal speichern wollen, muss es, wie bei der vorgestellten Webseite, direkt von Google aus dem Internet geladen werden. Das hat den Nachteil, dass Ihre Anwendung zum Start eine Internetverbindung immer benötigt und somit iPod touch-Benutzer und Besitzer eines WLAN-iPads Ihre App nicht ausführen können, wenn sie nicht gerade in der Nähe eines WLAN-Hotspots sind. Um dieses jQTouch-Beispiel als iPhone-Anwendung laufen zu lassen, müssen Sie wieder: •
Ein neues Xcode-Projekt mit PhoneGap-Vorlage erstellen und somit einen neuen Ordner anlegen.
•
Alle jQTouch-Komponenten, wie das jqtouch-Verzeichnis, das themes-Verzeichnis und optional das extensions-Verzeichnis in das www-Verzeichnis kopieren.
•
Den HTML-Code des jQTouch-Beispiels mit der Datei index.html im www-Verzeichnis wie gelernt verbinden.
•
In Xcode in den Project Settings ein Build Target auswählen.
•
Schließlich mit Xcode die Anwendung kompilieren und im iPhone-Simulator zum Laufen bringen.
Wenn Sie das alles befolgt haben, sehen Sie im iPhone-Simulator Folgendes:
Wenn Sie den Bildschirm genau betrachten, gibt es an seinem unteren Ende einen leeren, schwarzen Bereich. Dieser entsteht dadurch, dass jQTouch immer noch denkt, dass es in Safari laufe, den Vollbildmodus nicht erkennt und den Bereich dafür reserviert, die Webadresse einzugeben, wie in Safari üblich. Um das zu ändern, müssen Sie in die Datei jqtouch.css im Verzeichnis jqtouch gehen, die beim Laden der index.html mit eingebunden wird. Dort finden Sie relativ weit vorne folgende Zeilen: body > * { webkit backface visibility: hidden; webkit box sizing: border box; display: none; position: absolute;
3.3 iOS-Apps mit PhoneGap entwickeln
277
left: 0; width: 100%; webkit transform: translate3d(0,0,0) rotate(0) scale(1); min height: 420px !important; } body.fullscreen > * { min height: 460px !important; } body.fullscreen.black translucent > * { min height: 480px !important; }
Diese CSS-Definitionen bestimmen unter anderem die Mindesthöhe für den bodyBereich und sind leider innerhalb von PhoneGap gleich mehrfach falsch. Wenn Sie in Ihrer jQTouch-Anwendung eine graue oder schwarze Statusleiste verwenden – das definieren Sie innerhalb der Info.plist-Datei –, sollte das oben stehende CSS durch die folgenden Definitionen ausgetauscht werden: body > * { webkit backface visibility: hidden; webkit box sizing: border box; display: none; position: absolute; left: 0; width: 100%; webkit transform: translate3d(0,0,0) rotate(0) scale(1); min height: 460px !important; }
Richtig, die Definitionen für body.fullscreen und body.fullscreen.back-translucent können Sie löschen, da sie von PhoneGap und Xcode ohnehin nicht erkannt werden. Verwenden Sie in Ihrer jQTouch-Anwendung keine Statusleiste – Status bar is initially hidden-Einstellung in der Datei Info.plist – oder eine transparente, schwarze Statusleiste, ersetzen Sie die oben stehenden CSS-Definitionen durch folgenden Code: body > * { webkit backface visibility: hidden; webkit box sizing: border box; display: none; position: absolute; left: 0; width: 100%; webkit transform: translate3d(0,0,0) rotate(0) scale(1); min height: 480px !important; }
278
Kapitel 3 – Native Anwendungen erstellen
Speichern Sie diese Änderungen ab, säubern Sie Ihr XcodeProjekt mit Clean, und rufen Sie anschließend Build and Run auf. Der Hintergrund sollte bis zum unteren Rand reichen und wie nebenstehend aussehen. Wenn Sie jetzt die Animationen testen, die mit jQTouch möglich sind, sieht man bereits überhaupt nicht mehr, dass hier nicht mit Objective-C, sondern einfach nur mit ein bisschen HTML, CSS und JavaScript programmiert wurde. Code im Xcode Editor bearbeiten Sie haben bislang immer einen externen Texteditor verwendet, wenn Sie HTML-, CSS- oder JavaScript-Code bearbeitet oder neu erstellt haben. Xcode enthält bereits einen eingebauten Editor, der gerade bei den folgenden Beispielen das Arbeiten erleichtert. Sie müssen nicht immer zwischen Ihrem externen Texteditor und Xcode hin- und herschalten, sondern können jeglichen Code innerhalb eines Programms schreiben, verändern und schließlich auch ausführen. Um eine Datei in Xcode zu bearbeiten, wählen Sie sie einfach links unter Groups & Files aus. Der Code wird anschließend automatisch im Hauptfenster von Xcode angezeigt:
Bild 3.40: Die verschiedenen Graustufen auf der linken Seite des Codefensters markieren einzelne Codebereiche, also in sich geschlossene Funktionen oder Bereiche, in denen ein bestimmtes Tag gilt. Sobald Sie mit der Maus in dieses Feld gehen, können Sie einzelne Codebereiche ein- und ausblenden und so nur die Codeteile sehen, die für Sie gerade relevant sind.
3.3 iOS-Apps mit PhoneGap entwickeln
3.3.3
279
Mit PhoneGap und Xcode direkt auf einem iOS-Gerät testen
Sie haben bisher gesehen, wie Sie aus einer Webanwendung eine eigenständige iOS-App entwickeln können. Dabei werden alle HTML-Funktionen, die Sie bislang gelernt haben, unterstützt, da PhoneGap, wie am Anfang dieses Kapitels beschrieben, zwar nativen Code erstellt, die Inhalte aber in einem WebView-Fenster anzeigt, das die gleichen Eigenschaften und Fähigkeiten wie der mobile Safari-Browser besitzt. PhoneGap kann aber noch mehr und bietet Ihnen eine Brücke zwischen diversen Gerätefunktionen wie Vibration, Kamerazugriff, Bewegungssensoren und noch einiges mehr. Diese Funktionen können Sie in unseren Webcode über PhoneGaps JavaScript-APIs mit einbinden, allerdings im iOS Simulator nur begrenzt testen. Aus diesem Grund sehen wir uns jetzt kurz an, wie man die mit Xcode erstellten iOS-Anwendungen auf ein Gerät bekommt. Eines gleich vorweg: Um iOS-Anwendungen auf dem iPhone, dem iPad oder iPod touch zu testen, ist die kostenpflichtige Teilnahme am iPhone Developer-Programm erforderlich. Wir sind bei der Beschreibung des iOS SDK bereits darauf eingegangen – siehe Kapitel 3.2.1, »Entwicklungsumgebung für iOS-Entwicklung einrichten«. Haben Sie die Mitgliedschaft für das iPhone Developer-Programm beantragt und sind Sie nach Zahlung der Jahresgebühr zugelassen, erhalten Sie von Apple eine E-Mail, mit der Sie das Developer-Programm aktivieren können. Ab sofort stehen Ihnen dann im iPhone Dev Center – https://developer.apple.com/iphone – erweiterte Funktionen zur Verfügung.
Bild 3.41: Eine Provisionsdatei (Provisioning File) stellt sicher, dass Sie als Entwickler mit Ihrer App und Ihrer Entwicklungsumgebung (Xcode) identifizierbar sind. Die Provisionsdatei muss auf dem von Ihnen genutzten mobilen Gerät und gleichzeitig auch auf Ihrem Mac installiert werden.
280
Kapitel 3 – Native Anwendungen erstellen
Eine dieser neuen Optionen ist ein Link zum iPhone Provisioning Portal – http://developer. apple.com/iphone/manage/overview. Ein Klick darauf bringt Sie zur gleichnamigen Seite und lässt Sie Ihre physischen iOS-Geräte für Testinstallationen konfigurieren. Ähnlich strikt wie bei der Anmeldung zum Entwicklerprogramm ist Apple auch, wenn es darum geht, die Anwendung auf einem Gerät zu testen bzw. letztendlich in den App Store zu stellen. Das alles klingt unheimlich kompliziert, ist es aber nicht. Im iPhone ProvisioningPortal finden Sie am unteren Ende der Seite den Development Provisioning Assistent. Sobald Sie Ihr iPhone, iPad oder Ihren iPod touch inklusive USB-Kabel zur Hand haben, kann es mit einem Klick auf Launch Assistent losgehen. Im Assistenten selbst können Sie sich mittels Continue und Go Back Schritt für Schritt weiterbewegen. 1. Zuerst werden Sie gebeten, eine Beschreibung zu einer App ID anzugeben. Eine App ID ist eine eindeutige Bezeichnung für eine Anwendung im Apple-App-Universum. Jede Anwendung im App Store hat ihre eigene App ID. Wenn eine App ID einmal angelegt ist, kann sie im Anschluss nicht mehr bearbeitet werden. Das gilt im Übrigen auch für die Beschreibung der App ID: Zwar muss sie nicht eindeutig sein, bearbeiten oder gar löschen können Sie sie dennoch nicht. Seien Sie daher relativ spezifisch in der Auswahl eines geeigneten Namens. Die eigentliche App ID erhalten Sie von Apple zugeteilt.
Bild 3.42: Für unsere OldtimerAnwendung schlagen wir den Namen Oldtimer Markt als App ID-Beschreibung vor.
2. Im nächsten Schritt geht es um Ihr mobiles Gerät: Sie müssen zuerst eine kurze Beschreibung zu diesem Gerät eingeben. Wenn Sie nur ein iPhone haben und mit diesem entwickeln möchten, dürfte die Wahl nicht so schwer fallen. Falls Sie aber planen, auf diversen Geräten zu testen, ist es hier sinnvoll, über griffige Namen nachzudenken, anhand deren sich die jeweiligen Geräte identifizieren lassen.
Bild 3.43: Eingeben der Gerätebeschreibung
3.3 iOS-Apps mit PhoneGap entwickeln
281
3. Jetzt geben Sie den Identifier Ihres Geräts ein. Jedes Apple-Gerät hat eine eindeutige ID, die über Xcode abgerufen werden kann. Schließen Sie Ihr Apple-Gerät per USBKabel an den Mac an, und gehen Sie bei laufendem Xcode in das Menü Window und dort auf den Menüpunkt Organizer. Den 40-stelligen Identifier-Code können Sie mit der Maus markieren, kopieren und in den Development Provisioning-Assistanten kopieren. 4. Jetzt geht es um Ihren Rechner. Unter Programme/Dienstprogramme finden Sie die Anwendung Schlüsselbundverwaltung, die viele auf Ihrem Computer verwendete Passwörter speichert – sofern Sie das autorisiert haben. Nach dem Start der Anwendung wählen Sie aus der Schlüsselbundverwaltung das Untermenü Zertifikatsassistent und darunter den Punkt Zertifikat einer Zertifizierungsinstanz anfordern.
5. Danach geben Sie Ihre E-MailAdresse sowie Ihren Namen an und wählen aus, dass das generierte Zertifikat auf Ihrer Festplatte gespeichert wird. Mit einem Klick auf Weiter bekommen Sie die Gelegenheit, die Datei certSigningRequest auf Ihrem Desktop zu speichern. Wieder zurück im Development Provisioning Assistant, wählen Sie im nächsten Schritt die soeben gespeicherte Datei aus. 6. Bevor Sie Ihr Provisioning Profile erhalten, müssen Sie ihm noch einen passenden Namen geben. Wir sind in unserem Beispiel nicht übermäßig kreativ und wählen einfach Oldtimer Markt Profil. Den Zertifikatsnamen können Sie nicht ändern, da er an den Namen des Developer-Programm-Kontos gebunden ist. Im nächsten Schritt wird die Profildatei erstellt, und im darauffolgenden Schritt kann diese auf Ihren Mac heruntergeladen werden. 7. Rufen Sie jetzt wieder Xcode in den Vordergrund, und ziehen Sie die soeben generierte und heruntergeladene Datei in das Organizer-Fenster – in dem Sie sich bereits den Geräte-Identifier geholt haben – oder lassen Sie das Dateisymbol wie im Assistenten gezeigt einfach auf das Xcode-Symbol fallen. In der Geräteansicht im Organizer sehen Sie jetzt den Namen des Provisioning Profile unter Provisioning aufgelistet.
282
Kapitel 3 – Native Anwendungen erstellen
Bild 3.44: Das Provisioning-Profil im Organizer
8. Zurück im jetzt schon bekannten Development Provisioning Assistant, können Sie wieder eine Datei herunterladen. Diesmal ist es das Entwicklungszertifikat, das wir auf dem iPhone, iPod touch oder iPad installieren. Die zum Download angebotene CER-Datei kann nach dem Herunterladen vom Assistenten mit der Maus angeklickt werden, um die Keychain Access-Anwendung aufzurufen und mit Add das Zertifikat zu speichern. Wenn Sie in das Hauptfenster der Keychain Access-Anwendung gehen und dort auf die Unterkategorie Keys klicken, sollten der private und der öffentliche Schlüssel sowie innerhalb des privaten Schlüssels Ihr iPhone Development-Zertifikat sichtbar sein. 9. Nach diesen vielen Schritten haben Sie es fast geschafft: Sie können jetzt den Xcode Organizer schließen und ein PhoneGap-Projekt öffnen. In dem Drop-down-Menü in der linken oberen Ecke wählen Sie jetzt statt Simulator den Punkt Device aus. Haben Sie bislang nur ein Gerät provisioniert, wird es automatisch ausgewählt. Falls Sie mehrere Geräte besitzen und angeschlossen haben, können Sie im gleichen Menü noch das gewünschte Gerät auswählen. Der bereits bekannte Build and Run-Button ruft ab sofort nicht mehr den Simulator auf dem Bildschirm auf, sondern installiert Ihre neue iPhone-PhoneGap-App direkt auf dem angeschlossenen Gerät.
3.3 iOS-Apps mit PhoneGap entwickeln
3.3.4
283
Native iOS-Systemfunktionen in PhoneGap einbinden
Bislang müssen Sie noch mit den Beschränkungen einer Webseite leben, obwohl Sie bereits eine richtige iOS-App erstellt haben: Die Kamera ist für uns weiterhin nicht erreichbar, Sie können keinen Vibrationsalarm auslösen, nicht auf das Adressbuch zugreifen und auch den Bewegungssensor nicht nutzen. Glücklicherweise bietet PhoneGap eine ganze Reihe von JavaScript-APIs, mit denen Sie den Webcode ergänzen und auf diese nativen Funktionen zugreifen können. Nutzen Sie native Funktionen, wenn Sie in den App Store möchten Uns ist keine feste Regel bekannt, aber wir haben von Fällen gehört, in denen Apps, die beispielsweise mit PhoneGap erstellt wurden, nicht in den App Store aufgenommen wurden, weil sie keine nativen Systemfunktionen hatten und sich nicht von einer Webanwendung unterschieden haben. Nun kann man Apple keinen Vorwurf daraus machen, dass der App Store für Anwendungen und nicht für Webseiten gedacht ist. Dennoch sollten Sie überlegen, wie gut Sie die im folgenden Abschnitt vorgestellten nativen Funktionen innerhalb Ihres Projekts sinnvoll verwenden können, wenn Sie die Absicht haben, Ihr PhoneGap-App im App Store zu verkaufen. Navigationsleisten Eines der markantesten Elemente einer iOS-Anwendung ist die Navigationsleiste am unteren Bildschirmrand. Sie kennen sie von einigen mitgelieferten Apps, beispielsweise von der iPod- bzw. Musikanwendung, in der Sie zwischen Listen, Interpreten, Titel, Alben und Mehr umschalten können. Die untere Navigationsleiste, im Englischen »Tab Bar« genannt, wird in iOS-eigenen Anwendungen wie hier innerhalb der Musikanwendung verwendet. Das gleiche Konzept findet sich aber auch in vielen Apps von Drittanbietern wieder und erlaubt das schnelle und immer präsente Umschalten zwischen diversen Hauptbildschirmen der App.
Bild 3.45: Wenn neue Inhalte in einer der Ansichten zur Verfügung stehen, wird das oft mit einem kleinen Indikator angezeigt. Im rechten Beispiel gibt es zwölf Neuigkeiten auf dem HomeBildschirm der Anwendung.
284
Kapitel 3 – Native Anwendungen erstellen
Theoretisch könnte eine derartige Leiste auch recht umständlich innerhalb einer Webanwendung mit CSS und JavaScript nachgebaut werden, jedoch macht PhoneGap es einfacher und bietet Ihnen entsprechende JavaScript-Funktionen, um diese nativen Bedienelemente in Ihre Anwendungen einzubauen. Zuerst sollte man wissen, dass das iOS uns bereits verschiedene Symbole und Namen zur Verfügung stellt. Falls eines dieser Icons gut zu den von Ihnen geplanten Funktionen und Bildschirmansichten innerhalb Ihrer App passt, empfehlen wir, so häufig wie möglich die System-Icons zu verwenden. Benutzer wissen in der Regel schon, was sie bedeuten, und Ihre App wird vom Anwender schneller verstanden. Symbol
Deutsche Bezeichnung
Englische PhoneGap JavaScriptBezeichnung Parameter
Bestwertung
Top Rated
tabButton:TopRated
Suche
Search
tabButton:Search
Anrufliste
Recents
tabButton:Recents
Topvideos
Most Viewed
tabButton:MostViewed
Neue Videos
Most Recent
tabButton:MostRecent
Mehr
More
tabButton:More
Verlauf
History
tabButton:History
Highlights
Featured
tabButton:Featured
Favoriten
Favorites
tabButton:Favorites
Downloads
Downloads
tabButton:Downloads
Kontakte
Contacts
tabButton:Contacts
Lesezeichen
Bookmarks
tabButton:Bookmarks
3.3 iOS-Apps mit PhoneGap entwickeln
285
Die englischen Begriffe sind viel weiter gefasst als die deutschen Übersetzungen. Leider können Sie, wenn Sie in PhoneGap auf die iOS-Symbole zurückgreifen, die Bezeichnungen nicht ändern. Daher müssen Sie aufpassen, wenn Sie beispielsweise den vordefinierten Button Most Recent wählen, dass dieser sich im Deutschen nur auf neue Videos bezieht und daran gebunden ist. Sie müssen aber nicht auf die vorgefertigten Icons zurückgreifen, sondern können auch eigene Piktogramme erstellen. Diese müssen folgendes Format und folgende Eigenschaften besitzen: •
30 x 30 Bildpunkte für Bildschirme in niedriger Auflösung.
•
60 x 60 Bildpunkte für den iPhone 4-Retina-Bildschirm.
•
PNG-Format mit transparentem Hintergrund.
•
Reinweißer Vordergrund ohne Schattenwurf etc.
Wir empfehlen Ihnen, generell das 60-x-60-Icon zu verwenden, da dieses Icon von älteren iOS-Geräten auf die benötigte Größe heruntergerechnet wird. Die Bezeichnung des Icons brauchen Sie nicht mit in die Grafik zu übernehmen. Im Gegensatz zu den vorgefertigten System-Icons können Sie hier die Bezeichnung frei im JavaScript-Aufruf wählen. Mit dem nächsten Beispielcode wollen wir Folgendes erreichen: Am unteren Bildschirmrand unseres iWebKit-Beispiels soll eine native Navigationsleiste mit vier antippbaren Bereichen angezeigt werden (linkes Bild). Drei der verwendeten Icons sollen vom System kommen, das Testauto-Icon wurde individuell erstellt. Wenn man auf Bestbewertung tippt, soll eine Meldungsbox erscheinen, die das bestätigt, und ein kleiner Zähler soll über dem Icon anzeigen, wie oft dieses Feld bereits angetippt wurde (mittleres Bild). Tippt man auf Testautos, wird die gleiche Seite neu geladen, allerdings ohne wieder eine ganz neue (und in dem Fall zusätzliche) Navigationsleiste anzuzeigen (rechtes Bild).
Bild 3.46: Nach dem Antippen von »Bestbewertung« wird das dazugehörige Symbol mit einem Zähler ausgezeichnet.
286
Kapitel 3 – Native Anwendungen erstellen
Hier der Beispielcode: Navigationsleiste <script type "text/javascript" charset "utf 8" src "phonegap.js"> <script type "text/javascript" charset "utf 8"> // Warten, bis PhoneGap geladen ist function onLoad() { document.addEventListener("deviceready", onDeviceReady, false); } // Sobald PhoneGap da ist, lade folgende Funktionen: function onDeviceReady() { window.uicontrols.createTabBar(); var toprated 0; window.uicontrols.createTabBarItem("toprated", "Egal was hier steht", "tabButton:TopRated", { onSelect: function() { navigator.notification.alert("Bestwertung angetippt"); window.uicontrols.updateTabBarItem("toprated", { badge: ++toprated }); } }); window.uicontrols.createTabBarItem("suche", "Auch egal", "tabButton:Search", { onSelect: function() { navigator.notification.alert("Suche angetippt"); window.uicontrols.updateTabBarItem("recents", { badge: ++recents }); } }); window.uicontrols.createTabBarItem("test", "Testautos", "/www/button.png", { onSelect: function() { document.location.href "index.html"; } }); window.uicontrols.createTabBarItem("anderes", "Buch", "tabButton:Bookmarks", { onSelect: function() {
3.3 iOS-Apps mit PhoneGap entwickeln
287
navigator.notification.alert("Lesezeichen angetippt"); } }); if (window.innerHeight 480) { window.uicontrols.showTabBar(); window.uicontrols.showTabBarItems("toprated", "suche", "test", "anderes"); } } Oldtimer Kontakt <span class "graytitle">Spitzen Oldtimer von VW & Porsche - <span class "name">Aktuelle Angebote<span class "arrow">
- <span class "name">Unsere VWs<span class "arrow">
- <span class "name">Unsere Porsche<span class "arrow">
- <span class "name">Reparaturen<span class "arrow">
- <span class "name">Preisrechner <span class "arrow">
288
Kapitel 3 – Native Anwendungen erstellen
3.3.5
Lokalisierte Button-Bezeichnungen
Wenn Sie diesen Beispielcode mit den bisherigen Xcode-Einstellungen ausführen, werden Sie mit großer Wahrscheinlichkeit die englischen Bezeichnungen Top Rated, Search und Bookmarks für die System-Icons erhalten. Das liegt daran, dass die App noch nicht für die Lokalisierung vorbereitet ist. Um das zu ermöglichen, müssen Sie einfach mit der Maus wieder auf die Info.plist-Datei klicken, dort die Einstellung Localized resources can be mixed mit in die Liste aufnehmen und durch einen Klick auf die Checkbox aktivieren. Speichern Sie die Info.plist-Datei, säubern Sie anschließend über Build/Clean Ihr Projekt, und lassen Sie es neu kompilieren. Wenn Sie Deutsch oder eine andere Sprache auf Ihrem virtuellen (oder richtigen) iOS-Gerät eingestellt haben, erscheinen jetzt die lokalisierten Bezeichnungen unterhalb der System-Icons. Analysieren wir jetzt, was im Code des vorhergehenden Beispiels gemacht wurde: Als Erstes wurde der JavaScript-Code in die Funktion onDeviceReady() gepackt, damit sichergestellt ist, dass die nativen JavaScript-Aufrufe erst dann ins Spiel kommen, wenn die Anwendung und PhoneGap komplett gestartet sind. Eine Navigationsleiste wird im Wesentlichen durch zwei JavaScript-Aufrufe: window.uicontrols.createTabBar();
und eine bestimmte Anzahl von: window.uicontrols.createTabBarItem("ID", "Label", "Button", { Anweisung };
bestimmt. Mit window.uicontrols.createTabBar() wird die eigentliche Leiste initialisiert. Diese Leiste sitzt am unteren Bildschirmrand und hat weder Icons noch Bezeichnungen. Diese werden durch einzelne Angaben von window.uicontrols. createTabBarItem() mit den jeweiligen Parametern hinzugefügt. Parameter
Beschreibung
ID
Eine selbst gewählte ID, die Sie später im Code verwenden, um das jeweilige Element innerhalb der Navigationsleiste anzusprechen.
Label
Eine frei wählbare Bezeichnung, die unterhalb des Icons angezeigt wird. Beachten Sie, dass, wenn Sie ein System-Icon verwenden, die Angaben unter Label ignoriert werden.
3.3 iOS-Apps mit PhoneGap entwickeln
289
Parameter
Beschreibung
Button
Entweder der Link zu einer eigenen Buttongrafik oder die Angabe des System-Buttontyps, wie beispielsweise tabButton:Search. Falls Sie eine eigene Grafik verwenden, muss hier der gesamte Pfad angegeben werden. Liegt die Grafik button.png beispielsweise im www-Verzeichnis, muss die Angabe des Links wie folgt aussehen: /www/button.png.
Anweisung
Über ein onSelect()-Event legen Sie hier fest, welche JavaScript-Anweisungen beim Antippen des jeweiligen Elements auf der Navigationsleiste auszuführen sind.
In diesem Beispiel verwenden wir zwei verschiedene Varianten der window. uicontrols.createTabBarItem()-Angabe: var toprated 0; window.uicontrols.createTabBarItem("toprated", "Egal was hier steht", "tab Button:TopRated", { onSelect: function() { navigator.notification.alert("Bestwertung angetippt"); window.uicontrols.updateTabBarItem("toprated", { badge: ++toprated }); } });
Zuerst definieren Sie die Variable toprated und setzen sie auf null. Dann rufen Sie window.uicontrols.createTabBarItem mit der ID toprated auf. Die ID ist unabhängig von der gewählten Variablen. Als Label-Text verwenden Sie irgendeinen Text, der ohnehin nicht angezeigt wird, da wir als Nächstes mit tab-Button:TopRated einen System-Button verwenden. Als Anweisung verwenden wir das Event onSelect(). Sobald der Benutzer auf das Navigationselement tippt, wird eine Meldungsbox angezeigt (zur Funktion navigator. notification.alert() kommen wir im übernächsten PhoneGap-Abschnitt). Diese Meldungsbox bestätigt noch einmal, dass das richtige Feld angetippt wurde. Als Nächstes finden Sie die Zeile: window.uicontrols.updateTabBarItem("toprated", { badge: ++toprated });
Mit dieser Angabe wird das Navigationselement mit der ID toprated aktualisiert. In den geschweiften Klammern stehen die JavaScript-Anweisungen, die bewirken, dass die Variable toprated um eins erhöht wird und der kleine Zahlenindikator dann mit dem neuen Wert angezeigt wird. Die zweite Variante der window.uicontrols.createTabBarItem()-Angabe ist diese: window.uicontrols.createTabBarItem("test", "Testautos", "/www/button.png", { onSelect: function() { document.location.href "index.html"; } });
290
Kapitel 3 – Native Anwendungen erstellen
Hier wird ein Element mit der ID test und dem Label Testautos definiert. Diesmal wird das Label angezeigt, da kein System-Icon im nächsten Feld angegeben wird, sondern der Pfad und der Dateiname zu einer PNG-Grafik. Als Anweisung wird wieder ein onSelect()-Event verwendet, allerdings mit der Angabe, dass jetzt eine HTML-Seite aufgerufen wird und nicht nur eine Meldungsbox. In unserem Beispiel rufen wir die Datei index.html auf – also wieder die Seite, die die Definitionen für die Navigationsleiste enthält. Würden wir nicht einen besonderen Trick verwenden, würde sich bei jedem Antippen dieses Elements und dem Neuladen der Seite eine neue Navigationsleiste auf die andere legen, und zwar so lange, bis der Bildschirm mit Navigationsleisten gefüllt ist. Das umgehen wir durch die folgende Angabe, in der es darum geht, die mit den bisherigen JavaScript-Aufrufen definierten Elemente und die Navigationsleiste auch anzuzeigen: if (window.innerHeight 480) { window.uicontrols.showTabBar(); window.uicontrols.showTabBarItems("toprated", "suche", "test", "anderes"); }
Die Funktionen window.uicontrols.showTabBar() und window.uicontrols. showTabBarItems() bewirken also die Anzeige aller vorher festgelegten Elemente – um genau zu sein, aller Elemente, die bei window.uicontrols.showTabBarItems() mittels ihrer ID angegeben wurden. Beide Funktionen werden aber nur aufgerufen, wenn auf dem Bildschirm noch 480 Bildpunkte an Höhe frei sind. Hätten Sie zwei Navigationsleisten definiert, würde der verfügbare Bildausschnitt kleiner als 480 Bildpunkte sein, und die Anzeige einer weiteren Navigationsleiste würde durch die ifBedingung unterbunden. Jetzt haben Sie sicher gemerkt, dass wir das Beispiel ohne die Statusleiste kopiert haben. Wenn Sie die schwarze oder graue Statusleiste innerhalb der Info.plist-Datei anschalten, müssen Sie auch den window.innerHeight-Parameter verkleinern und auf mindestens 460 Bildpunkte setzen. Native Kopfzeile Die von uns verwendete Kopfzeile ist Teil der Webseite und wird beim Scrollen der Seite aus dem Bildschirm herausgeschoben. Viele native Anwendungen verwenden feste und statische Kopfzeilen im Zusammenhang mit oder auch ohne Navigationsleiste. PhoneGap bietet Ihnen ebenfalls die Möglichkeit, eine solche Kopfleiste mit zwei ähnlichen JavaScript-Funktionen zu definieren: window.uicontrols.createToolBar(); window.uicontrols.setToolBarTitle("Anwendungstitel");
Leider ist dieses Element nicht besonders stabil integriert. Insbesondere im Zusammenhang mit der Navigationsleiste treten oft Probleme und Inkompatibilitäten auf. Möchten Sie eine feste Leiste am oberen Bildschirmrand mit dem Anwendungstitel verwenden, sind die beiden JavaScript-Aufrufe eine gute Möglichkeit. In allen anderen Fällen empfehlen wir aber, auf HTML- und CSS-Definitionen zurückzugreifen.
3.3 iOS-Apps mit PhoneGap entwickeln
291
Native Systemmeldungen: Meldungsboxen, Vibration und Audio-Beep Sie haben bereits im letzten Beispiel mit der systemeigenen Meldungsbox Bekanntschaft gemacht, als wir uns bestätigen ließen, auf welches Element in der Navigationsleiste der Benutzer getippt hatte. Zu den nativen Systemmeldungen gehören aber auch noch der Vibrationsalarm sowie die Beep-Funktion, die auf einem iPhone eine im www-Verzeichnis befindliche Audiodatei (im WAV-Format) abspielt. Das Beispiel soll vier antippbare Flächen besitzen, die entweder das iPhone vibrieren lassen, eine WAV-Datei abspielen oder eine der beiden Systemmeldungen anzeigen:
Bild 3.47: Wenn Sie schnell etwas anzuzeigen haben: Titel und Button-Label sind vom System vorgegeben – den eigentlichen Meldungstext können Sie selbst festlegen (linkes Bild). Die Angabe des Titels und die des Button-Labels sind zwar optional, lassen aber den Dialog verständlicher wirken (rechtes Bild).
Hier der Beispielcode: Meldungsboxen & Co. <script type "text/javascript" charset "utf 8" src "phonegap.js"> <script type "text/javascript" charset "utf 8"> // Warten, bis PhoneGap geladen ist function onLoad() { document.addEventListener("deviceready", onDeviceReady, false); } function onDeviceReady() { } // Standard Meldungsbox anzeigen function simpleShowAlert() {
292
Kapitel 3 – Native Anwendungen erstellen
navigator.notification.alert('Hallo! Ich bin eine einfache Alert Box'); } // Selbst definierte Meldungsbox anzeigen function complexShowAlert() { navigator.notification.alert('Erwischt. Du hast schon wieder auf dem iPhone rumgetippt!','Das gibts ja nicht!', 'Ok ich machs nicht wieder'); } // Melodie spielen function playBeep() { navigator.notification.beep(); } // Vibrieren function vibrate() { navigator.notification.vibrate(1000); } Meldungsboxen & Co. - <span class "name">Standard Alert Box
- <span class "name">Selbstdefinierte Box
- <span class "name">Melodie spielen
- <span class "name">Vibrrrrrieren
Wie Sie bemerkt haben, ruft die JavaScript-Funktion navigator.notification. alert() eine systemeigene Meldungsbox auf. Diese muss mindestens den Meldungstext als Parameter beinhalten: navigator.notification.alert('Hallo! Ich bin eine einfache Alert Box');
3.3 iOS-Apps mit PhoneGap entwickeln
293
Sie kann aber optional auch Definitionen für Titel und Button-Label im folgenden Format enthalten: navigator.notification.alert('Meldungstext','Titel','Button Label');
Falls Sie von Ihrer Anwendung aus in bestimmten Situationen ein Audiosignal abspielen möchten, geht das mit der im Code sichtbaren Zeile navigator.notification.beep. Auf einem iPhone wird in diesem Fall eine Audiodatei abgespielt, die •
sich im www-Verzeichnis befindet,
•
im WAV-Format vorliegt und
•
nicht länger als 29 Sekunden lang sein darf.
Das Abspielen einer WAV-Datei erfolgt nur beim iPhone. Wird diese Funktion mit PhoneGap für Android verwendet, spielt das Telefon den eingestellten Standardklingelton für Benachrichtigungen ab. PhoneGap enthält bereits eine mitgelieferte beep.wav-Datei, die sich im Verzeichnis phonegap-iphone/PhoneGapTutorial/www/ befindet. Kopieren Sie diese Datei einfach in das www-Verzeichnis Ihres Projekts, und schon klingelt Ihr iPhone beim Aufruf der playBeep()-Funktion. Zum
Abschluss macht die JavaScript-Anweisung navigator.notification. vibrate() genau das, was sie auch namentlich verspricht: Sie lässt das Telefon
vibrieren. Auch hier gibt es wieder einen Unterschied zwischen dem iPhone und einem Android-Gerät. Auf einem iPhone wird der Wert in der Klammer, der die Vibrationslänge in Millisekunden angibt, nicht unterstützt. Das iPhone hat einen festen internen Wert und ignoriert diesen Parameter. Anders Android: Hier kann man die Länge der Vibration in Millisekunden angeben. Systemseitige Ladeanzeige Wir haben alle schon zu lang auf diesen Bildschirm geschaut, und als iPhone-Anwender kennen wir ihn auch alle: den Bildschirm mit dem aus kleinen Linien bestehenden Kreis, der sich so schön dreht, wenn wir wieder einmal auf Informationen aus dem Netz warten und diese geladen werden. Mit etwas JavaScript kann diese Ladeanzeige in verschiedenen Darstellungsweisen auch in PhoneGap-Anwendungen mit eingebaut werden. Die systemseitige Ladeanzeige kann zum einen als kleines Overlay auf der aktuellen Seite dargestellt werden. Das ist hier schwer zu sehen: Aber der Overlay-Hintergrund ist nicht komplett schwarz, sondern sehr dunkel transparent. Alternativ kann eine Ladeanzeige auch den gesamten Bildschirm einnehmen. Das ist besonders dann sinnvoll, wenn nicht nur Teile der Seite nachgeladen werden müssen, sondern sich nach dem fertigen Laden besonders viel auf der Seite ändert oder sogar komplett neuer Inhalt angezeigt wird.
294
Kapitel 3 – Native Anwendungen erstellen
Bild 3.48: Anzeigemöglichkeiten der systemseitigen Ladeanzeige.
Wir haben das wieder anhand eines kleinen Beispiels verdeutlicht: Ladebildschirm <script type "text/javascript" charset "utf 8" src "phonegap.js"> <script type "text/javascript" charset "utf 8"> // Warten, bis PhoneGap geladen ist function onLoad() { document.addEventListener("deviceready", onDeviceReady, false); } // Sobald PhoneGap da ist, lade folgende Funktionen: function onDeviceReady() { } function LadeVollbild(dauer) { optionen { 'duration': dauer, 'backgroundOpacity': 0.4, 'labelText': "Laden..." }; navigator.notification.loadingStart(optionen); } function LadeInline(dauer) {
3.3 iOS-Apps mit PhoneGap entwickeln
295
optionen
{ 'duration': dauer, 'bounceAnimation': true, 'fullScreen': false, 'labelText': "Laden..."
}; navigator.notification.loadingStart(optionen); } Ladebildschirm - <span class "name">Ladebildschirm Vollbild
- <span class "name">Ladebildschirm Overlay
Das Beispiel ist zwar nicht besonders zweckdienlich, verdeutlicht aber sehr gut, wie vielseitig ein Ladebildschirm aufgerufen werden kann. Der eigentliche Aufruf der Ladeanzeige erfolgt mit navigator.notification.loadingStart();, wobei der Funktion zahlreiche Optionen mit auf den Weg gegeben werden können: Parameter
Beispielwert Beschreibung
duration
10
Die Anzeigedauer des Ladebildschirms in Sekunden.
bounceAnimation
true
Die Ladeanzeige kann mit einer Animation auf den Bildschirm gerufen werden. Obwohl die Option auch bei der Vollbildladeanzeige zur Verfügung steht, sieht sie beim Overlay besser aus.
fullScreen
false
Standardmäßig ist die Vollbildladeanzeige definiert, sie kann aber mit dieser Option auch auf ein Overlay verkleinert werden.
strokeOpacity
0.2
Hiermit wird der Kreisstrich bestimmt.
296
Kapitel 3 – Native Anwendungen erstellen
Parameter
Beispielwert Beschreibung
strokeColor
FF0000
Hiermit wird die Farbe der Schrift bestimmt.
backgroundOpacity 0.4
Hiermit wird die Transparenz des Hintergrunds bestimmt.
labelText
Wenn Sie diesen Parameter nicht angeben, wird der englische Begriff Loading angezeigt. Allerdings ist er nicht in die Systemlokalisierung eingebunden und wird auch bei eingestellter deutscher Sprache in Englisch angezeigt. Deshalb ist es ratsam, mit diesem Parameter einen alternativen Text anzuzeigen.
Laden
In diesem Beispiel werden einige unterschiedliche Parameter je nach gewählter Funktion zusammengefasst und dann mit navigator.notification.loadingStart() aufgerufen. In einem wirklich nützlichen Szenario würden wir aber den Benutzer nicht für eine feste Anzahl von Sekunden auf einen Ladebildschirm sehen lassen, sondern im Hintergrund wirklich noch etwas tun und erst nach erledigter Arbeit die Ladeanzeige ausblenden. Das geschieht mit dem Aufruf von navigator.notification.loadingStop(). Sobald diese Funktion aufgerufen wird, ist die Ladeanzeige nicht mehr sichtbar.
3.3.6
Ladeanzeige in der Statusleiste
Insbesondere wenn Daten im Hintergrund geladen werden, ist das durch ein kleinen, sich drehenden Kreis in der Statusleiste sichtbar. Auch PhoneGap kann diese native Funktion über JavaScript und die folgenden Aufrufe ansprechen: •
navigator.notification.activityStart() – startet die Ladeanzeige.
•
navigator.notification.activityStop() – blendet die Ladeanzeige wieder aus.
Das funktioniert natürlich nur unter einer Bedingung: Die Statusleiste, egal ob in Grau oder Schwarz, muss eingeschaltet und darf nicht über Status bar is initially hidden in der Info.plist-Datei deaktiviert sein.
3.3.7
Adressbucheinträge neu anlegen und abrufen
Ein weiterer Bereich, der für eine Webanwendung unerreichbar ist, für eine mobile Anwendung jedoch sehr nützlich sein kann, ist die Kontaktliste bzw. das Adressbuch des Telefons. PhoneGap bietet vollen Zugriff auf das Adressbuch durch diverse JavaScriptAPIs. Eintrag anlegen Im ersten Beispiel erstellen wir eine einfache Oberfläche, in der der Benutzer den Vorund Nachnamen sowie die Telefonnummer eines neuen Kontakts eingeben kann. Das Formular enthält einen Speichern-Button, der die Daten direkt ins Adressbuch schreibt und mit einer Meldungsbox bestätigt. Da PhoneGap auch leere Einträge in das Adress-
3.3 iOS-Apps mit PhoneGap entwickeln
297
buch speichern würde, stellen wir vorher sicher, dass der Benutzer mindestens den Voroder Nachnamen eingegeben hat.
Bild 3.49: Links: Über eine einfache Oberfläche kann der Benutzer Vorname, Nachname und Telefonnummer eingeben und im Adressbuch speichern. Mitte: ob der Eintrag erfolgreich war, wird dadurch überprüft, dass die neuen Einträge wieder aus dem Adressbuch abgerufen und angezeigt werden. Rechts: Bei einem erfolgreichen Eintrag ist der neue Kontakt auch im iOS-Adressbuch sichtbar. <meta name "viewport" content "width default width; user scalable no" /> Kontakte <script type "text/javascript" charset "utf 8" src "phonegap.js"> <script type "text/javascript" charset "utf 8"> function onBodyLoad() { } function addContact() { // Variablen aus dem Form Feld lesen var neuvorname document.kontaktinfo.vorname.value; var neuname document.kontaktinfo.nachname.value; var neutelefon document.kontaktinfo.telefon.value; if (neuvorname ! "" || neuname ! "") { // Parameter bilden
298
Kapitel 3 – Native Anwendungen erstellen
var neuadresse { 'firstName': neuvorname, 'lastName': neuname, 'phoneNumber': neutelefon }; navigator.contacts.newContact(neuadresse, addContact Return); } else { navigator.notification.alert("Mindestens Vor }
oder Nachnamen eingeben");
} function addContact Return(contact) { if (contact) { navigator.notification.alert(contact.firstName + " " + contact.lastName, "Neu im Adressbuch", "Danke"); } } Kontakt hinzufügen - <span class "name">Vorname
- <span class "name">Name
- <span class "name">Telefon
Zuerst erstellen Sie ein HTML-Formular und geben ihm die ID bzw. den Namen kontaktinfo. Wird es durch Antippen des Buttons abgeschickt, wird über das JavaScript-Event onClick die Funktion addContact() aufgerufen. In dieser Funktion erhalten Sie über das Document Object Model die Werte, die im Formular eingegeben wurden, und weisen folgende neue Variablen zu:
3.3 iOS-Apps mit PhoneGap entwickeln
299
// Variablen aus dem Form Feld lesen var neuvorname document.kontaktinfo.vorname.value; var neuname document.kontaktinfo.nachname.value; var neutelefon document.kontaktinfo.telefon.value;
Nur wenn die Variable neuvorname oder die Variable neuname nicht leer ist, wird der für den JavaScript-Aufruf notwendige Parameter aus Vorname, Nachname und Telefonnummer gebildet … if (neuvorname ! "" || neuname ! "") { // Parameter bilden var neuadresse { 'firstName': neuvorname, 'lastName': neuname, 'phoneNumber': neutelefon };
… und letztendlich an die JavaScript-API übergeben, die den neuen Eintrag im Adressbuch erstellt und anschließend die JavaScript-Funktion addContact Return() aufruft: navigator.contacts.newContact(neuadresse, addContact Return);
Die Funktion macht nichts anderes, als den gerade erstellten Eintrag aus der Datenbank zu holen und den gespeicherten Vor- und Nachnamen in einer Meldungsbox anzuzeigen. Einträge abrufen Jetzt wollen wir die gespeicherten Einträge wieder aus dem iPhone-Adressbuch herausholen und eine Liste mit allen im Adressbuch befindlichen Vornamen und Nachnamen erstellen. Zusätzlich wollen wir die von der JavaScript-API zur Verfügung gestellten optionalen Einstellungen ebenfalls berücksichtigen.
Bild 3.50: Links: Das Beispiel besitzt einen einfachen Bildschirm, über den alle Kontakte innerhalb des Adressbuchs abgerufen werden können. Rechts: Verändert man keinen der vorgegebenen Werte, werden die Vor- und Nachnamen der ersten 20 Kontakte aus Ihrem Adressbuch gelesen und dargestellt.
Dass es sich um die ersten 20 und nicht etwa um die ersten 50 Einträge handelt, wird im Beispiel mit dem Wert unter Einträge/Seite festgelegt. Wollen Sie die ersten 20 Einträge überspringen, können Sie unter Startseite in unserer Beispielanwendung eine 2 eingeben.
300
Kapitel 3 – Native Anwendungen erstellen
Bild 3.51: Links: Ein sehr nützliches Feature ist der Suchfilter. Er arbeitet nicht nur mit expliziten Anweisungen, sondern versteht auch Platzhalter wie * am Ende des Namens. Rechts: Im gezeigten Beispiel liefert die Suchanfrage wen* alle Namen, die mit »wen« beginnen.
Im folgenden Beispielcode sehen Sie, wie wir das gemacht haben: <meta name "viewport" content "width default width; user scalable no" /> Kontakte <script type "text/javascript" charset "utf 8" src "phonegap.js"> <script type "text/javascript" charset "utf 8"> function onBodyLoad() { } // Initiale Variablen festlegen var nameFilter ""; var pageSize 20; var pageNumber 1; function kontakteAnzeigen() { // Variablen durch eventuelle Formulareingaben aktualisieren nameFilter document.kontaktsuche.suchfilter.value; pageSize document.kontaktsuche.maxContacts.value; pageNumber document.kontaktsuche.startpage.value; // Aufruf der selbst definierten getContacts Funktion getContacts(parseInt(pageSize), parseInt(pageNumber), nameFilter); } function getContacts(pageSize, pageNumber, nameFilter) { debug.log("getContacts"); var fail
function() {};
3.3 iOS-Apps mit PhoneGap entwickeln
var options
301
{};
// Die Anzahl von Eintraegen pro Seite kann mit der Option pageSize festgelegt werden if (pageSize) options.pageSize pageSize; // Als Option kann auch die anzuzeigende Seitenzahl angegeben werden if (pageNumber) options.pageNumber pageNumber; // Der Namensfilter kann mit * einen Platzhalter beinhalten if (nameFilter) options.nameFilter nameFilter; // JavaScript Aufruf, um Kontaktdaten zu erhalten navigator.contacts.getAllContacts(getContacts Return, fail, options); } function getContacts Return(contactsArray) { // So lange die Schleife durchlaufen, bis alle Kontakte empfangen wurden for (var i 0; i < contactsArray.length; i++) { var firstName contactsArray[i].firstName; var lastName contactsArray[i].lastName; if (i + 1 !
contactsArray.length)
// Nachname und Vorname in einem neuen div Element // und Listenelement definieren newDiv document.createElement("div"); newDiv.ClassName "content" newDiv.innerHTML '- <span class "name">' + lastName + ", " + firstName +'
'; // Neues Element und Inhalt in DOM uebernehmen listen div document.getElementById("footer"); document.body.insertBefore(newDiv, listen div); } navigator.notification.alert("Alle Namen importiert", "Fertig", "Vielen Dank"); } Kontakte anzeigen
302
Kapitel 3 – Native Anwendungen erstellen
- <span class "name">Suchfilter
- <span class "name">Einträge/Seite
- <span class "name">Startseite
Zuerst haben wir wieder ein iPhone-typisches Formular mit iWebKit angelegt, um dort einige für die API optionale Parameter abzufragen. Falls der Benutzer im Formular keine anderen Werte eingibt, werden die am Anfang des Codes definierten Werte benutzt: var nameFilter ""; var pageSize 20; var pageNumber 1;
Die JavaScript-API getAllContacts(), die wir später im Beispiel verwenden, gibt uns nicht nur die Adressinformationen aus dem Adressbuch wieder, sondern die Ausgabe lässt sich über diese drei Parameter auch anpassen: Variable
Bedeutung
nameFilter
Über die Variable nameFilter kann ein Suchbegriff übermittelt werden, der die API veranlasst, nur Namen zurückzugeben, die mit dem Suchbegriff übereinstimmen. Die Angabe eines Platzhalters am Ende eines Namens mittels eines *-Zeichens ist ebenfalls möglich.
pageSize
Ein Adressbuch kann ziemlich lang und komplex sein. Manche Benutzer haben Hunderte, wenn nicht sogar Tausende Adresseinträge auf ihrem Telefon. Wenn Sie die API aufrufen, ist es sinnvoll, diese in verschiedene Seiten zu unterteilen. Über pageSize legen Sie fest, wie viele Einträge pro Seite zurückgegeben werden sollen.
pageNumber
Mittels pageNumber können Sie angeben, welche Seite Sie aus dem Adressbuch abfragen und von welcher Sie Adressdaten erhalten möchten. Haben Sie beispielsweise ein Adressbuch mit 60 Einträgen 20 definiert, erhalten Sie bei der Angabe von und pageSize pageNumber 2 die Adressbucheinträge 21 bis 40 von der API.
3.3 iOS-Apps mit PhoneGap entwickeln
Das
Formular
ruft
beim
Antippen
des
Anzeigen-Buttons
die
303
Funktion
kontakteAnzeigen() auf und übergibt über das Document Object Model die
einzelnen Formularwerte an die Variablen. Anschließend wird die selbst definierte getContacts()-Funktion aufgerufen: getContacts(parseInt(pageSize), parseInt(pageNumber), nameFilter);
Interessant bei diesem Aufruf ist, dass die Variablen pageSize und pageNumber auf einen Integer-Ganzzahlwert gebracht werden. Nachdem die Variablen als Optionsparameter zusammengefasst wurden, erfolgt der eigentliche JavaScript-API-Aufruf getAllContacts(), der bei Erfolg die Funktion getContacts Return (contactsArray) aufruft. Die Variable contactsArray.length bestimmt, wie viele Adresseinträge von der API empfangen wurden, und eine for-Schleife läuft so lange durch, bis alle Vor- und Nachnamen erfasst sind. for (var i 0; i < contactsArray.length; i++) { var firstName contactsArray[i].firstName; var lastName contactsArray[i].lastName;
Bei jedem Durchlauf der Schleife wird der aktuelle Vorname in die Variable firstName und der Nachname in die Variable lastName übertragen und auch gleich auf dem Bildschirm ausgegeben. Um direkt von dieser JavaScript-Funktion auf den Bildschirm zu schreiben, benutzen wir wieder das Document Object Model, erstellen einen neuen div-Container über: newDiv
document.createElement("div");
… und weisen diesem Container die Klasse content und den folgenden Inhalt zu: newDiv.ClassName "content" newDiv.innerHTML '- <span class "name">' + lastName + ", " + firstName +'
';
Pro Durchlauf wird also ein neuer ul- und li-Bereich mit dem Nachnamen und dem Vornamen erstellt, über folgende Zeilen oberhalb des footer div-Containers geschrieben und somit angezeigt: // Neues Element und Inhalt in DOM übernehmen listen div document.getElementById("footer"); document.body.insertBefore(newDiv, listen div);
Ziemlich einfach, oder? Etwas komplizierter ist es, die E-Mail-Adressen oder Telefonnummern eines Kontakts auszulesen. Grund dafür ist, dass ein Kontakt mehrere Telefonnummern oder E-Mail-Adressen besitzen kann. Pro Kontakt wird deshalb für Telefon und E-Mail ein neues Array angelegt. Würden wir der ersten Schleife, in der der Vor- und Nachname abgefragt wird, noch die folgende Schleife hinzufügen, würden wir zu einem Kontakt auch die Telefonnummer erhalten: for (var j 0; j < contactsArray[i].phoneNumbers.length; ++j) { var phoneNumber contactsArray[i].phoneNumbers[j].label + ": " + contactsArray[i].phoneNumbers[j].value;
304
Kapitel 3 – Native Anwendungen erstellen
navigator.notification.alert(phoneNumber, lastName + ', ' + firstName, "Aha. Danke.") }
Dabei ist anzumerken, dass wir in contactsArray[i].phoneNumbers[j].value die Nummer erhalten, in contactsArray[i].phoneNumbers[j].label jedoch auch die dazugehörige Kategorie sehen und damit bestimmen können, ob es sich um eine Privat-, Arbeits- oder Mobilnummer handelt.
Bild 3.52: Über die JavaScript-API erhalten Sie nicht nur die Telefonnummern eines Kontakts, sondern auch die dazu passenden Nummerntypen (Arbeit, privat etc.). Das Gleiche gilt für die verschiedenen E-Mail-Adressen eines Kontakts.
Einen nahezu identischen Code können Sie verwenden, um die E-Mail-Felder abzufragen: for (var k 0; k < contactsArray[i].emails.length; ++k) { var email contactsArray[i].emails[k].label + " : " + contactsArray[i].emails[k].value; navigator.notification.alert(email, lastName + ', ' + firstName, "Aha. Danke.") }
3.3.8
Kamera und Fotobibliothek
Jetzt kommen wir zu einem sehr spannenden Bereich: der Kamera und dem Zugriff auf die Fotobibliothek durch die PhoneGap JavaScript-API. Auch wenn die Steuerung oder zumindest der Zugriff auf die Kamera keinen Platz in der HTML5-Spezifikation gefunden hat, ist das mit Sicherheit eines der Features, die in den nächsten Jahren ihren Stammplatz in vielen Browsern erhalten werden. Google hat bereits in der Entwicklerkonferenz I/O 2010 angekündigt, dass eine der zukünftigen Android-Versionen mit einem Webbrowser ausgeliefert wird, der vollen Zugriff auf die eingebaute Kamera bietet. Bis wir aber in dieser Zukunft angekommen sind, können wir mittels PhoneGap ebenfalls die Kamera in unseren Anwendungen nutzen.
3.3 iOS-Apps mit PhoneGap entwickeln
305
Unser Beispiel Foto-Betrachter besteht aus sehr einfachem Beispielcode und lässt dem Benutzer die Wahl, ob er ein Foto aus der Fotobibliothek auswählen oder direkt eins mit der Kamera aufnehmen möchte. Um Fotos aus der Fotobibliothek auszuwählen, wird der iOS-Standardbildschirm aufgerufen. Sie brauchen ihn nicht zu programmieren, denn er wird automatisch durch den API-Aufruf auf den Bildschirm gebracht. Nach der Auswahl erscheint das Foto dann im schwarz markierten Fotobereich unserer kleinen Beispielanwendung.
Bild 3.53: Ein markiertes Fotos erscheint nach der Auswahl im Fotobereich der Beispielanwendung.
Nicht viel anders sieht es bei der Benutzung der Kamera aus: Auf die Kamerafunktionen selbst haben Sie keinen Einfluss, und es wird die iOS-Kameraanwendung aufgerufen. Nachdem Sie ein Bild aufgenommen und für gut befunden haben, wird es ebenfalls im schwarzen Fotobereich unseres Foto-Betrachters dargestellt.
Bild 3.54: Ein aufgenommenes Bild wird im Fotobereich des FotoBetrachters dargestellt.
Wie immer hier erst einmal der Beispielcode:
306
Kapitel 3 – Native Anwendungen erstellen
<meta name "viewport" content "width default width; user scalable no" /> Foto Betrachter <script type "text/javascript" charset "utf 8" src "phonegap.js"> <script type "text/javascript" charset "utf 8"> function onBodyLoad() { var sourceType; } function holeFoto(auswahl) { // Kamera oder Fotobibliothek? if (auswahl 'bibliothek') { sourceWahl 0; } else { sourceWahl 1; } var options { quality: 50 } options["sourceType"] sourceWahl; // Kamera bzw. Fotobibliothek API Aufruf navigator.camera.getPicture(onSuccess, onFail, options); } // Wird nur aufgerufen, wenn ein Bild erfolgreich geholt wurde function onSuccess(imageData) { document.getElementById("bild").src "data:image/jpeg;base64," + imageData; } // Wird im Fehlerfall aufgerufen function onFail(meldung) { navigator.notification.alert('Folgender Fehler aufgetreten: ' + meldung); } Foto Betrachter -
3.3 iOS-Apps mit PhoneGap entwickeln
307
-
Wie Sie sehen, ist ein Bildbetrachter, der die native Fotobibliothek und die iPhoneKamera benutzt, keine hohe Kunst, sondern insgesamt nur ein API-Aufruf. Den Rest macht PhoneGap fast von allein. Doch der Reihe nach: Wir stellen den Benutzer mit zwei Buttons vor die Wahl, ob er das Foto aus der Bibliothek auswählen oder mit der Kamera aufnehmen möchte. Falls Sie das Beispiel im Simulator, auf einem iPod touch oder einem iPad ausprobieren, wird der Button zur Kameraaufnahme nicht funktionieren. Die Anwendung stürzt weder ab, noch gibt es eine Fehlermeldung – es passiert eben einfach gar nichts, da diese Geräte wie auch der Mac-Simulator keine Kamera besitzen. Die Variable sourceType bestimmt, wo das Foto ausgewählt wird. Wird sourceType auf 0 gesetzt, wird beim API-Aufruf die Fotobibliothek aufgerufen. Wird im Gegenzug der Wert auf 1 gesetzt, wird die Kamera benutzt. Eine weitere Option ist der qualityParameter: Dieser kann auf einen Wert von 0 bis 100 gesetzt werden und bestimmt die Qualität des gespeicherten Fotos. Mit der folgenden Zeile wird die API aufgerufen, und die Optionsparameter werden übergeben: navigator.camera.getPicture(onSuccess, onFail, options);
Geht alles gut und ist der API-Aufruf erfolgreich, wird die selbst definierte Funktion onSuccess(), anderenfalls die Funktion onFail() aufgerufen. function onSuccess(imageData) { document.getElementById("bild").src imageData; }
"data:image/jpeg;base64," +
Die Funktion onSuccess enthält als Ergebnis des navigator.camera.getPicture()API-Calls die Bilddaten in der Variablen imageData. Die Bilddaten eines jeden Fotos sind mit Base64 codiert, also einem Verfahren zur Codierung von 8-Bit-Binärdateien in eine normale Zeichenfolge. Die Bilddaten in der Variablen imageData sind also nichts weiter als ein normaler String. Diesen String können Sie entweder im lokalen Speicherbereich (Local Storage) speichern, an einen Server übermitteln oder einfach als Bild innerhalb unserer Anwendung
308
Kapitel 3 – Native Anwendungen erstellen
anzeigen. Da wir in PhoneGap arbeiten, nehmen Sie dazu das HTML-Tag img und konstruieren den dazugehörigen source-Parameter, indem wir das Datenformat data:image/jpeg;base64 sowie die Bilddaten über den erstellten String in der Variablen imageData miteinander verbinden. Zum Schluss legen Sie mittels CSS für den Bereich, in dem das Foto angezeigt werden soll, einen schwarzen Hintergrund fest und wählen eine vordefinierte Anzeigegröße aus:
Würden Sie die CSS-Größenangaben im img-Tag nicht mit angeben, würde das Bild in Originalgröße angezeigt werden.
3.3.9
Geolocation
Die aktuelle Position eines Benutzers können Sie bereits mit jedem modernen WebKitBrowser erhalten. Glücklicherweise brauchen Sie Ihren Webcode für eine iOSAnwendung mit PhoneGap auch kaum umzuschreiben, da PhoneGap genau die gleichen JavaScript-API-Calls wie HTML5 verwendet: Methode
Beschreibung
geolocation.getCurrentPos Einfache One-Shot-Anfrage, um die aktuelle Position ition() des Benutzers einmalig zu erfragen. geolocation.watchPosition Übermittelt die aktuelle Position des Benutzers in einer bestimmten Frequenz. () geolocation.clearWatch()
Stoppt die automatische Übermittlung der aktuellen Position des Benutzers.
Neben dem Längen- und dem Breitengrad gibt die PhoneGap-API noch weitere Werte aus: •
Längengrad
•
Breitengrad
•
Höhe
•
Genauigkeit
•
Richtung
•
Geschwindigkeit
•
Zeit- und Datumsstempel
3.3 iOS-Apps mit PhoneGap entwickeln
309
Bild 3.55: Einfache Geolocation-Anfrage über PhoneGap.
Das folgende kleine Beispiel gibt genau diese Werte auf einer Seite aus: <meta name "viewport" content "width default width; user scalable no" /> One Shot Geo <script type "text/javascript" charset "utf 8" src "phonegap.js"> <script type "text/javascript" charset "utf 8"> function onBodyLoad() { } function holePosition() { // Geo One Shot API Aufruf navigator.geolocation.getCurrentPosition(onSuccess, onFail); } // Wird nur aufgerufen, wenn die Position erfolgreich geholt wurde function onSuccess(position) { var element document.getElementById('geolocation'); element.innerHTML 'Breitengrad: ' + position.coords.latitude + '
' + 'Längengrad: ' + position.coords.longitude + '
' + 'Höhe: ' + position.coords.altitude + '
' + 'Richtung: ' + position.coords.heading + '
' + 'Geschwindigkeit: ' + position.coords.speed + '
'
310
Kapitel 3 – Native Anwendungen erstellen
} // Wird im Fehlerfall aufgerufen function onFail() { navigator.notification.alert('Immer geht was schief!'); } One Shot als App
Das Beispiel ist schnell erklärt: Das Antippen des Buttons Wo bin ich? ruft die Funktion holePosition() auf, die dann den schon bekannten Geolocation-API-Aufruf vornimmt: navigator.geolocation.getCurrentPosition(onSuccess, onFail);
Bekommen wir die Geoposition, wird die Funktion onSuccess() ausgeführt, falls nicht, wird die Funktion onFail() aufgerufen. Beides sind selbst definierte JavaScript-Funktionen. Die Funktion onSuccess enthält die Positionsdaten in der Variablen position. Wir nehmen uns dann die einzelnen Werte vor und generieren einen HTML-String, der im body-Bereich der Seite angezeigt wird: var element document.getElementById('geolocation'); element.innerHTML 'Breitengrad: ' + position.coords.latitude + '
' + 'Längengrad: ' + position.coords.longitude + '
' + 'Höhe: ' + position.coords.altitude + '
' + 'Richtung: ' + position.coords.heading + '
' + 'Geschwindigkeit: ' + position.coords.speed + '
'
3.3 iOS-Apps mit PhoneGap entwickeln
311
3.3.10 Bewegungssensoren Als eine der letzten nativen APIs möchten wir Ihnen die API zum Auslesen des Accelerometers, also des Beschleunigungs- und Bewegungsmessers, vorstellen. Die Art und Weise, wie wir die API aufrufen werden, ist eng verwandt mit dem Aufrufen und Verwenden der Geoposition. PhoneGap kennt drei verschiedene JavaScript-APIs: Funktion
Erläuterung
accelerometer. watchAcceleration()
Übermittelt die aktuelle Lage des Geräts im dreidimensionalen Raum in einer festgelegten Frequenz.
accelerometer. clearWatch()
Stoppt die automatische Übermittlung der Lage des Geräts.
accelerometer. getCurrentAcceleration()
Übermittelt die aktuelle Lage des Geräts im Raum als One-Shot-Anfrage. Dieser API-Aufruf ist dem iPhone unbekannt, funkioniert aber beispielsweise auf Android-Geräten. Unter iOS müssen Sie immer die accelerometer.watchAcceleration()-API verwenden.
Als Beispiel dient eine Art virtuelle Wasserwaage, die keine Wasserblasen, sondern Koordinaten anzeigt. Wenn sich das Gerät allerdings genau im Hochformat befindet, also der Untergrund genau gerade ist, wird durch den navigator.notification. beep()-API-Call ein Ton ausgegeben. Wir verwenden wieder eine simple Oberfläche mit zwei Buttons, die selbst definierte JavaScript-Funktionen aufrufen, die wiederum entweder die accelerometer. watchAcceleration()-API oder die accelerometer.clearWatch()-API beinhalten. Alle 0,1 Sekunden wird die Lage des Telefons im dreidimensionalen Raum ausgewertet und die jeweilige Position auf der x-, y- und z-Achse angezeigt.
Bild 3.56: Auf einer einfachen Oberfläche wird alle 0,1 Sekunden die Lage des Telefons im dreidimensionalen Raum ausgewertet.
312
Kapitel 3 – Native Anwendungen erstellen
Virtuelle Wasserwaage <meta name "viewport" content "width default width; user scalable no" /> <script type "text/javascript" charset "utf 8" src "phonegap.js"> <script type "text/javascript" charset "utf 8"> // Festlegen der watchID var watchID null; // Warten, bis PhoneGap geladen ist function onLoad() { document.addEventListener("deviceready", onDeviceReady, false); } function onDeviceReady() { } function startAccelerometer() { // Als Aktualisierungsfrequenz legen wir 0,1 Sekunden fest var options { frequency: 100 }; // API Aufruf watchID navigator.accelerometer.watchAcceleration(onSuccess, onFail, options); } // Automatische Uebermittlung der Geraetelage beenden function stopAccelerometer() { if (watchID) { navigator.accelerometer.clearWatch(watchID); watchID null; } } // Wird nur aufgerufen, wenn Beschleunigungswerte erhalten wurden function onSuccess(acceleration) { var element document.getElementById('accelerometer'); element.innerHTML 'Beschleunigung/Lage X: ' + acceleration.x + '
' + 'Beschleunigung/Lage Y: ' + acceleration.y + '
' + 'Beschleunigung/Lage Z: ' + acceleration.z + '
';
0.01 && acceleration.y 0.99 && acceleration.y > 1.01 ) { navigator.notification.beep(); } } // Wird im Fehlerfall aufgerufen function onFail() { alert('Immer geht was schief!');
3.3 iOS-Apps mit PhoneGap entwickeln
313
} 3D Bewegungsbestimmung
Die virtuelle Wasserwaage besteht aus drei wichtigen JavaScript-Funktionen. Die erste dieser selbst definierten Funktionen ist startAccelerometer(), die durch das Antippen des Start-Buttons aufgerufen wird. Als einzige Option für den kommenden API-Aufruf kann die Frequenz angegeben werden, die festlegt, wie oft nach einer neuen Raumlage des Geräts geschaut werden soll. Bei einer Wasserwaage wollen wir ständige Aktualisierungen erhalten und setzen aus diesem Grund den Wert auf 0,1 Sekunden. Die Variable frequency wird, genau wie bei den automatischen Geopositionsaktualisierungen, in Millisekunden angegeben. Anschließend erfolgt der eigentliche API-Aufruf: watchID navigator.accelerometer.watchAcceleration(onSuccess, onFail, options);
Der Aufruf wird in der Variablen watchID festgehalten. Das ist wichtig, da Sie diese watchID dann wieder angeben müssen, wenn Sie z. B. die automatische Übermittlung der Raumpositionsdaten deaktivieren möchten. Wie bei den meisten anderen PhoneGap-APIs geben wir auch hier eine Funktion onSuccess an, die bei einer erfolgreichen Datenerfassung aufgerufen wird, und eine Funktion onFail, die im Fall eines Fehlers oder Problems aufgerufen wird. Die Beschleunigungsdaten werden in den Variablen acceleration.x, acceleration.y und acceleration.z gespeichert und alle 0,1 Sekunden auf einer HTML-Seite ausgegeben:
314
Kapitel 3 – Native Anwendungen erstellen
var element document.getElementById('accelerometer'); element.innerHTML 'Beschleunigung/Lage X: ' + acceleration.x + '
' + 'Beschleunigung/Lage Y: ' + acceleration.y + '
' + 'Beschleunigung/Lage Z: ' + acceleration.z + '
';
Die folgende Grafik verdeutlicht noch einmal, welche Werte Sie in welcher Lage erwarten können und wie die Achsen beispielsweise bei einem iPhone liegen:
Bild 3.57: Die Achsen des iPhones im Raum
Wenn Sie das Telefon ganz flach auf den Tisch legen, sollten Sie die Idealwerte von x = 0, y = 0 und z = –1 erhalten. Halten Sie das Telefon dagegen ganz genau hochkant, also die Unterseite gerade auf den Boden und genau senkrecht, soll sich die akustische Wasserwaage melden: if ( acceleration.x < 0.01 && acceleration.x > 0.01 && acceleration.y < 0.99 && acceleration.y > 1.01 ) { navigator.notification.beep(); } }
Mit dieser if-Abfrage schauen wir, ob sich x- und y-Wert im Bereich von ca. x = 0 und y = –1 befinden. Wenn ja, führen Sie den PhoneGap JavaScript-API-Call navigator.notification.beep aus und hören, wenn sich die Datei beep.wav im www-Verzeichnis des Projekts befindet, einen Piepton.
3.3.11 iPad-Apps mit PhoneGap erstellen Wenn Sie den Anweisungen im Buch bislang gefolgt sind, haben Sie Anwendungen für das iPhone und den iPod touch erstellt. Diese laufen natürlich auch auf einem iPad, allerdings in dem Modus, in dem Sie über einen Vergrößerungsbutton die Anwendung auf iPad-Größe hochskalieren können. In diesem Modus verliert nahezu jede Anwendung ihren Reiz und ihr besonderes Aussehen, und auch für die Benutzer eines iPads sind derartige Anwendungen eher Notlösungen.
3.3 iOS-Apps mit PhoneGap entwickeln
315
Bild 3.58: Unsere Beispiele wurden bisher als iPhone-Programme kompiliert und laufen auf einem iPad in einem kleinen Fenster. Das Fenster daneben kann auf die doppelte Größe hochskaliert werden, doch der Charme einer Anwendung geht dadurch verloren, und der größere Bildschirm wird nicht effektiv genutzt.
Da Xcode auch zur Erstellung von iPad-Anwendungen genutzt wird, lassen sich mit PhoneGap und entsprechendem HTML-Code ebenfalls vollwertige iPad-Anwendungen erstellen. Wir nehmen dazu in Xcode das oben gezeigte Beispiel zur Darstellung der Navigationsleiste und werden es jetzt als iPad-Anwendung kompilieren. 1. In Xcode gehen Sie in das Menü Project und wählen dort den Unterpunkt Edit Project Settings aus. Im daraufhin erscheinenden Fenster müssen Sie in den BuildBereich wechseln und unter Configuration im Drop-down-Menü den Eintrag All Configurations auswählen.
Bild 3.59: Auswahl der Option All Configurations.
316
Kapitel 3 – Native Anwendungen erstellen
2. Wählen Sie anschließend als Base SDK die neueste iOS-Version, in unserem Fall iPhone Device 4.0 unter iPhone OS Device SDKs aus:
Bild 3.60: Auswahl der Version4 des iPhones-SDK
3. Scrollen Sie dann in den Bereich Deployment und geben Sie dort unter Targeted Device Family einfach iPad an:
Bild 3.61: Auswahl des iPads als Zielsystem.
4. Sie können jetzt das Einstellungsfenster schließen, noch einmal sicherstellen, dass im oberen linken Menü in der Xcode-Hauptansicht der iPad Simulator ausgewählt ist, und anschließend auf Build and Run klicken. Sie werden sehen, dass aus der unproportionierten iPhone-App, die im iPhone Simulator auf einem iPad angezeigt wurde,
3.3 iOS-Apps mit PhoneGap entwickeln
317
nun eine richtige iPad-App geworden ist, die den vollen Bildschirm des iPads nutzen kann. In den Projekteinstellungen können Sie unter Targeted Device Family auch iPhone/ iPad auswählen, um eine Anwendung zu kompilieren, die auf dem iPhone und iPod touch, aber auch auf einem iPad läuft. Möchten Sie das tun, empfiehlt es sich, den folgenden Code mit in den Header einzubauen, um für die jeweilige Geräteklasse unterschiedliche CSS-Definitionen zu benutzen:
Wenn Sie eine Webanwendung bzw. App für das iPad erstellen, beachten Sie bitte folgende Punkte: •
Um den Bildschirm des iPads voll auszunutzen, empfehlen wir, Ihr Webdesign auf die Bildschirmdimensionen des iPads auszurichten: 768 x 1.024 Bildpunkte im Hochformat und 1.024 x 768 Bildpunkte im Querformat.
•
Das Programmsymbol einer iPad-App hat eine Bildgröße von 72 x 72 Bildpunkten. Die im PNG-Format vorliegende Datei kann in der Info.plist-Datei unter Icon File angegeben werden.
•
Auch der Startbildschirm einer iPad-App muss sich an der Bildschirmgröße orientieren. PhoneGap erstellt mit jedem neuen Projekt bereits zwei passende PNG-Dateien: Default-Landscape.png für einen Querformatstartbildschirm und Default-Portrait.png für die Hochformatvariante.
Mit den Änderungen in den Projekteinstellungen haben wir zwar den gesamten iPadBildschirm zur Verfügung, allerdings nimmt die Navigation immer noch die gesamte Bildschirmbreite ein. Ein beliebtes Navigationskonzept auf dem iPad ist eine statische Navigationsleiste auf der linken Seite und die Anzeige von dynamischen Inhalten auf der rechten Seite.
318
Kapitel 3 – Native Anwendungen erstellen
Bild 3.62: Die OldtimerAutohaus-Seite-App, für das iPad optimiert. Die Navigationsleiste bleibt statisch, während der Inhalt auf der rechten Seite scrollbar ist.
Was einfach aussieht, ist relativ umständlich zu programmieren. Vor einigen Jahren hätte man hierzu HTML-Frames benutzt, heute würde man für die Navigation und den Inhalt div-Container mit der CSS-Definition position:fixed erstellen. Diese CSSDefinition wird aber von mobilen Browsern aus guten Gründen nicht unterstützt. Die im letzten Screenshot gezeigte Navigationsleiste wurde mittels iScroll von Matteo Spinelli realisiert. Nach dem Einbinden der von ihm erstellten JavaScript-Bibliothek und den im iPad-Beispiel sichtbaren CSS-Definitionen müssen für die Navigationsleiste und den Inhaltsbereich nur unterschiedliche div-Container erstellt werden. In unserem Beispiel verwenden wir für die Leiste: Oldtimer Spiering - Aktuelle Angebote
- Unsere VWs
… und für den Inhaltsbereich: Spitzen Oldtimer von VW & Porsche <article> ...
Lesezeichen http://cubiq.org/iscroll Hier können Sie den iScroll-Code inklusive einiger Beispiele kostenlos herunterladen.
3.4 Android Apps mit PhoneGap entwickeln
3.4
319
Android Apps mit PhoneGap entwickeln
Wir haben die bisherigen Beispiele mit Xcode aus dem iOS SDK in native iOS-Anwendungen für iPhone, iPod touch und iPad umgewandelt. Fast alle Funktionen, die Sie dabei kennengelernt haben, lassen sich auch für Android umsetzen. 1. Zu Beginn werden wir uns wieder mit unserem Standardbeispiel aus der iWebKitVorstellung, der Oldtimer-HTML-Seite, beschäftigen. Dazu haben wir die Hauptbestandteile dieser Seite wieder in ein neues www-Verzeichnis innerhalb des phonegap-android-Ordners kopiert:
Bild 3.63: Die Beispiele im www-Verzeichnis.
Anders als in einer iOS-Anwendung erstellen Sie das www-Verzeichnis zuerst manuell, es wird nicht durch die Entwicklungsumgebung erzeugt. In dieses www-Verzeichnis gehören aber wie auch für iOS-Apps alle Bestandteile Ihrer mobilen Seite: HTMLSeiten, lokale Ressourcen (Bilder, Videos), CSS- und JavaScript-Dateien. Sie können theoretisch den www-Ordner überall auf Ihrem Rechner anlegen, der Einfachheit halber empfiehlt sich die temporäre Anlage allerdings in dem Ordner, in dem PhoneGap für Android installiert wurde. 2. Am Anfang jeder neuen Android-App steht nicht nur das passende HTML, sondern auch die recht umständliche Prozedur in der Konsole bzw. im Terminalprogramm. Rufen Sie dieses Programm auf und navigieren Sie in das Verzeichnis phonegapandroid. Von dort aus rufen Sie den folgenden Befehl (nur mit Ihren Parametern) auf: ./droidgap ~/android sdk mac 86 oldtimermarkt com.spiering.automarkt www/ ~/autohaus/androidapp
Sie haben diesen Aufruf schon einmal bei der Anlage des PhoneGap-Beispiels für Android kennengelernt. Die Angaben bedeuten: Parameter
Erläuterung
~/android-sdkmac 86
In diesem Verzeichnis befindet sich die Installation des Android SDK. Je nachdem, welche Android-Version Sie installieren, kann sich die Angabe des Verzeichnisses ändern.
oldtimermarkt
Der Name der Android-App.
320
Kapitel 3 – Native Anwendungen erstellen
Parameter
Erläuterung
com.spiering. automarkt
Das ist der Paketname der Anwendung. Der Paketname ist eine einzigartige ID Ihres Programms und sollte aus den Bestandteilen com.firmenname.programmname bestehen. Unter iOS wird das »Bundle ID« genannt. Mehr dazu können Sie im Abschnitt zum Verkauf Ihrer iOS-App in iTunes lesen.
www/
Der Verzeichnisname unseres www-Verzeichnisses mit dem HTMLCode, JavaScript, CSS und allen Grafiken. Da der www-Ordner in das phonegap-android-Verzeichnis kopiert wurde, müssen Sie hier keine langen Pfadnamen angeben.
~/autohaus/ androidapp
Das Zielverzeichnis, in dem »droidgap« alle Dateien und Verzeichnisstrukturen für das Android-Projekt anlegen soll.
Die Anweisungen im Terminal sehen bei erfolgreicher Ausführung wie folgt aus:
Bild 3.64: Blick auf das Terminalprogramm.
Dadurch wird diese Verzeichnisstruktur erstellt:
Bild 3.65: Die erstellte Verzeichnisstruktur.
3.4 Android Apps mit PhoneGap entwickeln
321
3. Sie können jetzt das Terminalprogramm bzw. die Konsole schließen und Eclipse öffnen. Wie auch beim ersten Android-Beispiel gehen Sie hier in das Menü File und wählen dort New Project aus. 4. Im folgenden Fenster wählen Sie im Ordner Android den Assistenten Android Project aus und bestätigen die Auswahl mit Next. Da wir unsere Quelldaten bereits erstellt haben, können wir unter New Android Project wieder Create project from existing source auswählen und das Verzeichnis angeben, das Sie gerade über Droidgap haben erstellen lassen. Zum Schluss wählen Sie in diesem Fenster eine Android-Version aus – in diesem Beispiel Android 2.2. 5. Dass Sie nun eventuell in der Problems-Anzeige eine oder mehrere Fehlermeldungen sehen, ist normal. Wie auch bei der vorherigen Installation müssen Sie jetzt im seitlichen Package Explorer unter unseren App-Namen den Ordner libs aufklappen und dort per rechter Maustaste und Build Path/Add to Build Path die Datei phonegap.jar in die Liste der Dateien aufnehmen, die beim Erstellen einer App berücksichtigt werden. 6. Nun können Sie erneut den App-Namen im Package Explorer markieren, auf den grünen Play-Button drücken und Android Application auswählen, da wir ja bereits bei der Installation des Android SDK und PhoneGap für Android unser virtuelles »Supertelefon« definiert hatten. Nach einer kurzen Weile sollte dann der Android-Emulator starten und unsere eigene Android App zeigen. Bevor wir damit beginnen, einige der nativen Funktionen in unserer Android-Anwendung zu testen, müssen noch zwei Dinge erledigt werden: die Android-JavaScriptBibliothek von PhoneGap in den Code einbinden und – um die nativen Funktionen auch ordentlich testen zu können – die App auf ein richtiges Gerät übertragen.
322
Kapitel 3 – Native Anwendungen erstellen
Die erste Aufgabe, die JavaScript-Bibliothek einzutragen, ist einfach: Wie in Xcode können Sie auch in Eclipse die Dateien komfortabel bearbeiten. Navigieren Sie im Package Explorer in das Verzeichnis assets und www (hier sind alle unsere HTML-, CSSund JavaScript-Dateien hineinkopiert wurden) und wählen Sie aus dem Kontextmenü für die index.html die Option Open With/Text Editor:
Bild 3.66: Öffnen der JavaScript-Bibliothek
In den head-Bereich der index.html tragen Sie einfach die folgende Zeile ein: <script type "text/javascript" src "phonegap.js" charset "utf 8">
3.4.1
Mit PhoneGap und Eclipse direkt auf einem Android-Gerät testen
Das Testen Ihrer Android App auf einem »echten« Gerät ist ein recht einfacher Prozess. Zwar können Sie bereits vieles mit dem Emulator testen, doch gerade wenn es um bestimmte Hardwarefunktionen wie beispielsweise Geoposition oder die Bewegungssensoren geht, kommen Sie um das Testen auf einem richtigen Android-Telefon nicht herum. Als ersten Schritt müssen Sie auf Ihrem Handy USB-Debugging aktivieren. Diese Option finden Sie in der Einstellungsanwendung unter dem Punkt Anwendungen und Entwicklung:
3.4 Android Apps mit PhoneGap entwickeln
323
Bild 3.67: USB-Debugging aktivieren.
Bevor Sie Ihr Gerät an den Computer anschließen, müssen Sie, wenn Sie unter Windows arbeiten, zuerst einen USB-Treiber installieren. Den Treiber können Sie von der Windows-USB-Treiber-Seite – http://bit.ly/xvSSl – herunterladen und die weiteren Anweisungen auf der Seite befolgen. Wenn Sie unter Mac OS X arbeiten, können Sie diesen Schritt überspringen.Schließen Sie jetzt Ihr Telefon über das USB-Kabel an den Rechner an. Da Sie das USB-Debugging aktiviert haben, erscheint unmittelbar nach dem Anstecken ein kleiner Käfer und die Meldung USB-Debugging verbunden auf dem Handybildschirm. Zurück in Eclipse, müssen Sie wie gewohnt nur auf den grünen PlayButton klicken. Die Anwendung wird in Sekundenschnelle auf dem Telefon installiert und ausgeführt. Einfach, oder? Sobald Sie das Telefon vom Rechner trennen und erneut auf Play klicken, führt Eclipse automatisch wieder den Emulator aus.
3.4.2
Eigene Programmsymbole erstellen und verwenden
Da wir noch keine neuen Icon-Dateien benannt und erstellt haben, verwendet unser Android-Beispiel noch das typische blaue Phone-Symbol, das sich gleich drei Mal in unserem Projektordner befindet:
Bild 3.68: Im Verzeichnis res befinden sich die drei Ordner drawable-hdpi für hochauflösende Bildschirme, drawable-mdpi für mittelauflösende Bildschirme und drawable-ldpi für Bildschirme mit niedriger Auflösung.
324
Kapitel 3 – Native Anwendungen erstellen
In diese Ordner werden jeweils die einzelnen nativen Grafikelemente einer Anwendung platziert, damit Android sich je nach verwendetem Gerät die am besten passende Grafik aussuchen kann. Wird nur eine Grafikgröße zur Verfügung gestellt, kann das AndroidSystem die Grafik hoch- oder herunterrechnen, doch für eine bestmögliche Anzeige empfiehlt es sich, drei verschiedene Größen zu erstellen. Wie Sie sich sicher schon gedacht haben, repräsentiert die Datei icon.png das jeweilige Programmsymbol in den Ordnern. Dabei hat es sich PhoneGap etwas einfach gemacht und einfach das Symbol aus der iPhone-Version in der gleichen Größe (57 x 57 Pixel) in alle drei Ordner kopiert. Das werden wir jetzt korrigieren, indem wir drei Symbolgrößen entsprechend den Android-Richtlinien erstellen: Bildschirmauflösung Gesamtgröße (a)
Symbolgröße (b)
Größe eines quadratischen Symbols (c)
drawable-hdpi
72 x 72
60 x 60
56 x 56
drawable-mdpi
48 x 48
40 x 40
38 x 38
drawable-ldpi
36 x 36
30 x 30
28 x 28
Jetzt haben Sie nicht nur drei verschiedene Bildschirmkategorien, sondern auch noch pro Kategorie drei unterschiedliche Größen. Keine Angst – Sie brauchen nur eine Icon-Größe pro Datei zu wählen – und zwar die Gesamtgröße (a). Allerdings geben die Android-Richtlinien vor, dass sich Ihr eigentliches Symbol je nach Form an der Symbolgröße (b) oder der quadratischen Symbolgröße (c) orientieren sollte.
Bild 3.69: Die Rahmen für die Programmsymbole
Ein rundes oder nicht quadratisches Programmsymbol sollte demnach in den Rahmen (b) passen, wobei die gesamte Symboldatei die Größe (a) besitzen muss. Ein quadratisches Programmsymbol sollte im Gegensatz dazu in den Rahmen (c) passen, da ein quadratisches Symbol optisch größer und massiver erscheint als ein Symbol, das keine quadratische Form besitzt.
3.4 Android Apps mit PhoneGap entwickeln
325
Programmsymbole mit einer Photoshop-Vorlage erstellen Falls Sie Photoshop benutzen, können Sie von der offiziellen Android-Seite eine Datei mit Photoshop-Vorlagen für Programmsymbole herunterladen: http://bit.ly/aQD089. Diese Vorlage enthält diverse für Programmsymbole empfohlene Materialstrukturen und hilft bei der Gestaltung eines eigenen Icons. Der innere Bereich kann auch mit einem Schlagschatten versehen werden, der auf dem (a)-Bereich sichtbar wird. Hier sind die empfohlenen Android-Photoshop-Schatteneinstellungen für die hdpi-Auflösung:
Bild 3.70: Schatten für hochauflösende Displays
Und hier die für die mdpi-Auflösung:
Bild 3.71: Schatten für mittelauflösende Displays
Schlagschatten werden für ldpi-Symbole aufgrund der geringen Icon-Größe nicht empfohlen. Haben Sie Ihre Symbole in den drei verschiedenen Größen erstellt, können
326
Kapitel 3 – Native Anwendungen erstellen
Sie die in den drei Verzeichnissen im res-Ordner befindlichen icon.png-Dateien mit den neuen Symbolen ersetzen. Bevor Sie die neuen Symbole im Emulator oder auf Ihren Android-Telefon sehen, müssen Sie in Eclipse im Menü Project den Punkt Clean auswählen und dann erst den grünen Play-Button drücken.
3.4.3
Einstellungen in der Datei AndroidManifest.xml
Im Laufe Ihrer Android App-Karriere werden Sie immer wieder Kurztrips zur Datei AndroidManifest.xml unternehmen. Innerhalb von Eclipse finden Sie die für die Android-Entwicklung wichtige Datei im Hauptverzeichnis Ihres Projekts. Um sie zu bearbeiten, führen Sie einfach einen Doppelklick auf den Dateinamen im Package Explorer aus. Die Manifestdatei enthält alle wichtige Informationen und Einstellungen, die zur Ausführung einer Android-App benötigt werden. Bevor auch nur eine Zeile Code Ihrer Android-Anwendung ausgeführt wird, werden die im Manifest zementierten Einstellungen gelesen und beachtet. In Eclipse können Sie im Manifest-Editor zwischen diversen Ansichten umschalten: Manifest, Application, Permissions, Instrumentation und dem XML-Bearbeitungsmodus AndroidManifest.xml. App auf bestimmte Bildschirmgrößen beschränken Wenn Sie in Ihrer App relativ statische Grafiken in einer bestimmten Größe verwenden, kann es mitunter sinnvoll sein, die App für ganz kleine oder ganz große Bildschirmgruppen nicht zur Verfügung zu stellen. Im Manifest-Bereich können Sie diese Einstellung vornehmen. Klicken Sie unter Manifest Extras auf Supports Screens und wählen Sie anschließend in der rechten Seite aus, ob bestimmte Bildschirmgruppen unterstützt (true) werden sollen oder nicht (false). Start im Querformat erzwingen Möchten Sie beispielsweise Ihre Android App unbedingt im Querformat starten lassen, ist das eine Einstellung, die Sie im Manifest vornehmen können. Klicken Sie dazu auf den Bereich Application am unteren Fensterrand, und wählen Sie dann unter Application Nodes Ihren Anwendungsnamen aus. Auf der rechten Seite erscheint dann eine ganze Reihe von Einstellungsmöglichkeiten, die sich global auf Ihre Anwendung auswirken.
Bild 3.72: Diese Einstellungen erzwingen den Start der App im Querformat.
3.4 Android Apps mit PhoneGap entwickeln
327
Setzen Sie Screen orientation auf landscape, klicken Sie bei Config changes auf Select und entfernen Sie das Häkchen bei orientation. Sie legen somit fest, dass die App auf jeden Fall im Querformat startet und der Benutzer die orientation, also die Ausrichtung, auch nicht ändern kann. Selbst wenn der Benutzer das Android-Telefon hochkant hält, wird sich der Bildschirm nicht mitdrehen. Android-Titelleiste ausblenden Die Android-Titelleiste ist der Bereich am oberen Rand des Bildschirms, in dem der App-Name steht und der direkt unterhalb der Statusleiste liegt. Bei kleineren PhoneGap-Android-Apps bekommen Sie sie nur für einen kurzen Augenblick zu sehen, nämlich nachdem PhoneGap gestartet ist und bevor der Inhalt der index.html aus dem wwwOrdner angezeigt wird. Über das Manifest können Sie die Anzeige der Titelleiste unterbinden. Hierzu bleiben Sie in den gleichen Application Nodes wie zur Einstellung des Querformats, geben aber unter Theme die folgende Zeile ein: @android:style/Theme.NoTitleBar
3.4.4
Android-App mit Menüfunktionen versehen
Der Umstand, dass PhoneGap eine native Android-Anwendung generiert, die im Wesentlichen Webinhalte innerhalb dieser Anwendung darstellt, macht die Programmierung leicht, beinhaltet aber eine Einschränkung, die wir gekonnt überbrücken müssen. Nahezu alle Android-Anwendungen besitzen Programmmenüs, die der Benutzer über die Menütaste aufrufen kann und die Zugriff auf oft benutzte Programmteile oder -funktionen bieten. Bei einer Webseite berücksichtigt man diese Menüs nie, da beim Antippen der Menütaste das Browsermenü erscheint und somit diese Funktion bereits durch den Browser belegt ist. Auch beim iPhone oder generell unter iOS spielt das keine Rolle, da es einfach keine Menütaste und auch keine klassischen Menüs gibt. In der PhoneGap-Community werden deshalb schon seit einiger Zeit Lösungen diskutiert, die bislang noch nicht komplett in die Codebasis von PhoneGap für Android eingeflossen sind. Daher müssen wir uns kurz selbst helfen, indem wir im Eclipse Package Explorer die Datei phonegap.js ansteuern und sie im internen Texteditor öffnen. Suchen Sie in dieser Datei nach dem Ausdruck menuKeyDown. Falls er da ist, wurde zumindest ein Teil des Codes in die offzielle PhoneGap-Codebasis übernommen. Falls nicht, fügen Sie einfach folgende Zeilen der phonegap.js hinzu: KeyEvent.prototype.menuTrigger function() { var e document.createEvent('Events'); e.initEvent('menuKeyDown'); document.dispatchEvent(e); }
328
Kapitel 3 – Native Anwendungen erstellen
Gehen Sie dann zur index.html des aktuellen Beispiels und schreiben Sie die folgenden Zeilen in den head-Bereich unterhalb der Zeile, mit der wir die phonegap.js-Datei in den Code laden: <script type "text/javascript" charset "utf 8"> // Menüleiste einblenden document.addEventListener("menuKeyDown", function(){ alert('Jemand hat den Menü Button angetippt!') }, false); // Warten, bis PhoneGap geladen ist function onLoad() { document.addEventListener("deviceready", onDeviceReady, false); } function onDeviceReady() { }
Bei der iOS-Entwicklung mit PhoneGap haben Sie bereits das Event deviceready kennengelernt, das die JavaScript-Funktion onDeviceReady aufruft, sobald PhoneGap komplett geladen ist. Das Event menuKeyDown ist ähnlich aufgebaut. Sobald ein Benutzer das Menüfeld oder die Menütaste auf einem Android-Gerät antippt, wird die definierte Funktion ausgeführt. In diesem Fall ist es einfach eine native Meldungsbox. Somit können wir zumindest feststellen, ob der Benutzer die Menütaste gedrückt hat, und eine entsprechende Funktion ausführen. Wenn wir uns sicher sind, dass unsere Android-Anwendung nicht über die vertikale Bildschirmgröße hinausgeht, können Sie sich auch mit diesem einfachen Skript behelfen, das auf Menütastendruck ein CSSOverlay anzeigt und es bei nochmaligem Druck wieder verschwinden lässt. Im head-Bereich definieren Sie zusätzliches CSS für die Box, in der das Menü dargestellt werden soll: <style type "text/css"> #menuoverlay { background color:rgba(255, 255, 255, 0.9); border:2px solid; border color:#736d73; left:0px; bottom:0px; width:100%; height:100px; z index:99; visibility:hidden; }
Weisen Sie das CSS der ID menuoverlay zu, und wählen Sie eine weiße Hintergrundfarbe mit 10 % Transparenz. Der Rand soll in einer dunkelgrauen Farbe erscheinen, und als Position wurde die linke untere Ecke gewählt, von der aus die 100 Pixel Höhe berechnet werden.
3.4 Android Apps mit PhoneGap entwickeln
329
Da das CSS-Overlay jeweils an- oder ausgeschaltet werden soll, sobald der Benutzer auf die Menütaste tippt, speichern Sie den aktuellen Anzeigestatus in der Variablen toggleID: // Festlegen des Toggle Status var toggleID 0;
Die Funktion showMenu() ruft die Funktion show() mit dem jeweiligen visibleoder hidden-Parameter auf, je nach Wert der toggleID-Variablen. Mit der Funktion show() sprechen Sie den später im body-Bereich definierten div-Container an, der durch die CSS-Definitionen am Anfang der Seite auf hidden, also unsichtbar, gesetzt wurde und hiermit angezeigt oder versteckt wird. // Menü anzeigen function showMenu() { if (toggleID 0) { toggleID 1; show('visible'); } else { toggleID 0; show('hidden'); } } // Menüfunktion definieren function show(status){ e document.getElementById('menuoverlay'); e.style.visibility status; }
Ganz zum Schluss, innerhalb des body-Bereichs, definieren Sie noch ein ganz einfaches div, das den Inhalt des kleinen Menüs enthält:
<small>Karte aufrufen
Wenn Sie den folgenden Code in das Beispiel integriert haben und eine entsprechende Grafik mit in das www-Verzeichnis kopieren, sollte Ihr Android-Bildschirm wie nebenstehend aussehen. Sollten Sie umfangreichere Android-Seiten erstellen und ein komplexeres Menü benötigen, empfehlen wir Ihnen, einen Blick auf das JavaScript-Paket von »Slide-in menu« zu werfen. Dieses frei benutzbare Paket kann ein Menü per JavaScript ein- und ausblenden. Allerdings ist der Code derzeit nur für ein Menü am oberen Bildschirmrand konzipiert. Ein Update, das das Menü wahlweise an allen Seiten anzeigen kann, wurde vom Autor bereits in Aussicht gestellt. Weitere Informationen und den Code finden Sie unter http://cubiq.org/slide-in-menu.
330 3.4.5
Kapitel 3 – Native Anwendungen erstellen
Original-Android-Grafiken in Ihren Projekten verwenden
Wäre es nicht prima, wenn Sie genau die gleichen Menügrafiken in Ihren Projekten verwenden könnten, die ein Benutzer auch in den normalen Android-Anwendungen findet? Kein Problem – Sie haben diese Grafiken bereits versteckt auf Ihrer Festplatte. In Ihrem Android SDK-Ordner befindet sich das Verzeichnis platforms, das die heruntergeladenen Plattformversionen enthält. Wählen Sie dort den Ordner mit der neuesten Version aus, und legen Sie eine Kopie der darin befindlichen android.jar-Datei an. Sie erhalten dann eine neue Datei im gleichen Verzeichnis (oder in einem Verzeichnis Ihrer Wahl), bei der Sie die Dateiendung von .jar in .zip umbenennen. Eine JAR-Datei ist nämlich nichts anderes als ein ZIP-Archiv, nur unter einem anderen Namen.
Bild 3.73: Entpacken Sie die ZIP-Datei, und navigieren Sie in das Verzeichnis res, in dem Sie im Ordner drawable-hdpi alle vom System verwendeten Grafiken und Symbole im PNGFormat finden.
3.4.6
Native Android-Systemfunktionen integrieren
In den folgenden Abschnitten gehen wir auf die verschiedenen nativen Android-Funktionen ein, die über PhoneGap und JavaScript von Ihrem Webcode aus ansteuerbar sind. Wir werden uns dabei mit den optischen und funktionalen Unterschieden zwischen Android und iOS beschäftigen, da sich viele der APIs nicht nur ähneln, sondern teilweise identisch aufgerufen werden und funktionieren wie unter PhoneGap für iOS. Falls Sie gleich hierher gesprungen sind und nicht das iOS-Kapitel zu diesem Thema gelesen haben, empfehlen wir Ihnen, es als Vorbereitung zu überfliegen. Systemmeldungen, Vibration und Klingeltonalarm Die Systemmeldungsbox haben wir bereits im Menübeispiel kennengelernt, wobei wir sie nur mit dem simplen JavaScript-Aufruf alert(); aufgerufen haben. Selbst wenn wir die PhoneGap-API mit folgendem Beispielcode nehmen, erhalten wir nur das unten angezeigte Ergebnis: navigator.notification.alert('Jemand hat den Menü Button angetippt!','Titel','Button')
3.4 Android Apps mit PhoneGap entwickeln
331
Bild 3.74: Die Werte für den Titel oder die Buttons werden ignoriert.
Selbst auf einem in deutscher Sprache eingestellten Android-Telefon wird der Titel immer Alert und die beiden Auswahlbuttons OK und Cancel benannt. Bessere Nachrichten gibt es zum Vibrationsalarm: Im Gegensatz zum iPhone können Sie hier die Länge der Vibration in Millisekunden angeben: navigator.notification.vibrate(5000);
Dieser API-Aufruf lässt unser Android-Handy insgesamt fünf Sekunden vibrieren. Während Sie unter iOS eine Tondatei mit in das www-Verzeichnis kopieren mussten, damit ein Ton für den Klingeltonalarm gespielt wurde, ist das unter PhoneGap für Android nicht notwendig. Hier wird automatisch der Klingelton ausgewählt, den der Benutzer in den Geräteeinstellungen unter Töne als Benachrichtigungston eingestellt hat. Der Aufruf im Code könnte kaum einfacher sein: navigator.notification.beep();
Fotos von der Kamera einbinden Auch unter Android können Sie auf die Kamera zugreifen, Bilder direkt in Ihre Anwendung laden und dort weiterverwenden. Was bislang nicht möglich ist, ist der Zugriff auf die Fotobibliothek. Benutzer können somit nur Bilder innerhalb Ihrer Android App aufnehmen und keine bereits aufgenommenen Fotos verwenden.
Bild 3.75: Von unserer Beispielanwendung aus können wir wieder die native Android-Kamera ansteuern. Auf die Elemente in der Kameraanwendung haben wir keinen Einfluss.
332
Kapitel 3 – Native Anwendungen erstellen
Bild 3.76: Sobald das Bild aufgenommen ist, wird es wieder in einer Variablen gespeichert, die wir in unserem Beispiel sichtbar machen.
3.4.7
Android und Kameraanwendungen
Bei der Betrachtung der Kamera-APIs unter Android müssen Sie beachten, dass jeder Gerätehersteller seine eigene Kameraanwendung schreiben kann. Unter iOS gibt es eine Kameraanwendung, nämlich die von Apple. In der Android-Welt wollen sich die Hersteller mit ihren eigenen Versionen von Android oft voneinander unterscheiden. Sehr häufig wird die Kameraanwendung deshalb von verschiedenen Herstellern geändert oder neu geschrieben. Beispielsweise hat ein Google Nexus One eine etwas andere Anwendung als ein HTCGerät mit der Sense-UI. Das resultiert daraus, dass die einzelnen Kameraanwendungen unterschiedlich stabil sind und unterschiedlich gut mit PhoneGap zusammenarbeiten. Auf den meisten von uns getesteten Telefonen hatten wir keine Probleme, wir wissen aber von anderen, dass die Kamera auf manchen Telefonen abstürzt oder keine Ergebnisse liefert. Das sollte Sie nicht unbedingt davon abhalten, diese Funktion zu benutzen, da sie, wie gesagt, auf den meisten derzeitigen Android-Geräten funktioniert. Weil wir im Beispiel nicht mehr die Fotobibliothek berücksichtigen müssen, können wir unseren Beispielcode für Android wesentlich vereinfachen: <meta name "viewport" content "width default width; user scalable no" /> Foto Betrachter <script type "text/javascript" charset "utf 8" src "phonegap.js"> <script type "text/javascript" charset "utf 8"> function onBodyLoad() { } function holeFoto() {
3.4 Android Apps mit PhoneGap entwickeln
333
// Kamera bzw. Fotobibliothek API Aufruf navigator.camera.getPicture(onSuccess, onFail, { quality: 50 } ); } // Wird nur aufgerufen, wenn ein Bild erfolgreich geholt wurde function onSuccess(imageData) { document.getElementById("bild").src "data:image/jpeg;base64," + imageData; } // Wird im Fehlerfall aufgerufen function onFail(meldung) { navigator.notification.alert('Folgender Fehler aufgetreten: ' + meldung); } Foto Betrachter
Wie Sie sehen, haben wir jede Menge Code aus dem iPhone-Beispiel entfernt. Auch im API-Aufruf selbst können Sie auf den source-Parameter verzichten, da nur die direkte Ansprache der Kamera möglich ist. Der quality-Parameter ist auch unter Android gültig, allerdings haben wir diese Option direkt in den API-Aufruf eingebaut: // Kamera bzw. Fotobibliothek API Aufruf navigator.camera.getPicture(onSuccess, onFail, { quality: 50 } );
334
Kapitel 3 – Native Anwendungen erstellen
Geoposition Die Geopositions-API entspricht auch unter Android dem W3C-Standard und wird mit den gleichen Parametern wie unter PhoneGap für iOS aufgerufen. Somit stehen unter Android die bereits bekannten drei Methoden zur Verfügung: •
geolocation.getCurrentPosition
•
geolocation.watchPosition
•
geolocation.clearWatch
Im Beispiel für iOS hatten wir die aktuelle Position mit fünf verschiedenen Variablen ausgewertet. Es scheint, dass navigator.geolocation.getCurrentPosition keine Ergebnisse für die Höhe liefert, sondern dass wir nur die aktuellen Positionskoordinaten erhalten. Die selbst definierte JavaScript-Funktion onSuccess() können wir demnach minimieren: function onSuccess(position) { var element document.getElementById('geolocation'); element.innerHTML 'Breitengrad: ' + position.coords.latitude + '
' + 'Längengrad: ' + position.coords.longitude }
Bewegungssensoren Die virtuelle Wasserwaage können wir aus dem iOS-Beispiel nahezu ohne Codeänderungen übernehmen. PhoneGap für Android verwendet auch hier die gleichen Aufrufe. Allerdings sind die Daten, die in der Funktion onSuccess() angezeigt werden, anders als auf einem iPhone: function onSuccess(acceleration) { var element document.getElementById('accelerometer'); element.innerHTML 'Beschleunigung/Lage X: ' + acceleration.x + '
' + 'Beschleunigung/Lage Y: ' + acceleration.y + '
' + 'Beschleunigung/Lage Z: ' + acceleration.z + '
'; }
Um den gleichen Effekt wie unter iOS zu erzielen, müssen wir die if-Bedingung anpassen: if ( acceleration.x < 0.1 && acceleration.x > 0.1 && acceleration.y < 9.7 && acceleration.y > 9.5 ) { navigator.notification.beep(); }
3.4.8
Zusammenfassung
Insgesamt kann man sagen, dass PhoneGap für Android sicher hier und da noch Nachholbedarf gegenüber der iOS-Variante besitzt. Dies bekommt man vor allem zu spüren, wenn man in seiner Anwendung auf native UI-Elemente wie beispielsweise Menüs oder Pop-up-Menüs zurückgreifen möchte. Hier müssen Sie heute noch mit viel Kreativität herangehen. Zahlreiche Frameworks wie jQTouch, Sencha Touch (http://www.sencha. com/products/touch/) und vor allen Dingen auch jQuery Mobile (http://jquerymobile.com) haben bereits vernünftige Anwendungen erstellen lassen.
335
4
Webanwendungen und native Apps veröffentlichen
Wenn Sie diese Zeilen lesen, haben Sie tatsächlich bereits Ihre erste mobile HTML5Webanwendung oder native Anwendung erstellt. Herzlichen Glückwunsch! Jetzt wollen wir Ihnen natürlich auch zeigen, wie Sie Ihre Arbeit veröffentlichen können. Dabei liegt ein großes Augenmerk natürlich auf der Veröffentlichung von nativen Anwendungen im iTunes App Store und im Android Market, doch auch für reine Webanwendungen gibt es Distributionsmöglichkeiten, die wir Ihnen jetzt zeigen werden.
4.1
Apple Web Apps-Katalog
Wenn Sie eine Webanwendung erstellt haben, die auf einem iPod touch und auf einem iPhone läuft und gut aussieht, lassen Sie sie doch von Apple bewerben. In den meisten Märkten außerhalb der USA ist das relativ unbekannt, doch Apple besitzt auf seiner globalen Webseite apple.com einen Katalog mit mehreren Tausend HTML5-Webanwendungen. Sie erreichen diesen Katalog unter http://www.apple.com/webapps/ auf Ihrem Desktop-Browser. Dieser Katalog ähnelt dem Downloadkatalog für Mac-Software auf der Apple-Seite und unterteilt die vielen Web Apps in verschiedene Kategorien. Entstanden ist der Katalog 2007, als das erste iPhone veröffentlicht wurde und es noch keine Möglichkeit für Entwickler gab, Anwendungen für das Telefon zu schreiben. Die einzige Möglichkeit für Entwickler, anwendungsähnliche Inhalte für das iPhone aufzubereiten, waren Web Apps. Zwar ist der Katalog dadurch schon etwas älter, allerdings finden Sie nahezu jeden Tag viele neue Einträge. Im Apple Web Apps-Katalog ist keine Shoppingfunktionalität enthalten. Das wäre auch wenig sinnvoll, da sich Ihre Web App öffentlich im Internet befindet und sie theoretisch jeder aufrufen kann. Den Katalog gibt es auch nur in englischer Sprache. Um im Web Apps-Katalog gelistet zu werden, müssen Sie als Apple Developer registriert sein. Sie benötigen nicht die kostenpflichtige Mitgliedschaft im iPhone Developer-Programm, die kostenlose Anmeldung als Entwickler ist ausreichend.
336
Kapitel 4 – Webanwendungen und native Apps veröffentlichen
Bild 4.1: Der Apple Web Apps-Katalog.
Der Aufnahmeprozess wird über die Seite http://developer.apple.com/submission/iphone durchgeführt. Sie müssen sich als Erstes mit Ihrer Apple ID anmelden und anschließend dem iPhone Web Application Submission Agreement – also der Vereinbarung zur Einreichung einer iPhone-Webanwendung – zustimmen. Lesen Sie sich die Vereinbarung in Ruhe ganz durch, dennoch möchten wird gleich hier auf ein paar wichtige Punkte hinweisen: •
Ihre Webanwendung muss sich als iPhone-optimierte Webanwendung anfühlen und auch so funktionieren. Das meint Apple mit der ersten Bedingung, die besagt, dass eine eingereichte Webanwendung den iPhone-Webentwicklungsrichtlinien entsprechen muss. Ihre Chancen, in den Katalog aufgenommen zu werden, stehen sehr schlecht, wenn Sie eine einfache Webseite einreichen, die nicht iOS-optimiert ist. Mit den im Buch vorgestellten Techniken und insbesondere den von uns verwendeten CSS- und JavaScript-Frameworks wie iWebKit 5 und jQTouch sind Sie auf der sicheren Seite.
•
Ihre Webanwendung sollte zum Einreichungszeitpunkt fertig programmiert und getestet sein. Kaputte Links, nicht funktionierende Buttons oder fehlerhafte Grafiken sollten nicht mehr Bestandteil Ihrer Web App sein.
•
Auch wenn die Webanwendung in den Apple Web Apps-Katalog aufgenommen wird, sind Sie weiterhin für das Betreiben und das Hosten der Webseite verantwortlich. Apple wird nur aus dem Katalog auf Ihre Webseite verlinken.
Sind Sie mit der Vereinbarung einverstanden und haben Sie sie bestätigt, kommen Sie zu der Seite, in der Sie diverse Angaben zu Ihrer Webanwendung machen können. Diese Angaben beinhalten unter anderem die Links zu Ihrer mobilen Web App (Application Page), den Namen (Application Title), eine Kurzbeschreibung in Englisch (Product Summary) und eine ausführlichere Produktbeschreibung (Product Description). Die Wahl der richtigen Kategorie ist wichtig, damit interessierte Katalogbesucher sie später
4.1 Apple Web Apps-Katalog
337
leichter finden. Die Angabe der Lizenzform deutet darauf hin, dass Apple einfach die Seite zum Einstellen von Mac OS X-Anwendungen kopiert hat. Zum Abschluss müssen Sie noch ein Icon in der Größe 128 x 128 und einen Screenshot hochladen.
Bild 4.2: Gleichheit hat ihren Preis: Um in den Web-App-Katalog aufgenommen zu werden, müssen klare Regeln bei der Erstellung eines Screenshots befolgt werden.
Sie können leider nicht einfach einen Screenshot von Ihrem iPhone oder vom Simulator machen, da Apple eine Screenshot-Vorlage erstellt hat, die Sie verwenden müssen. Diese Vorlage können Sie von der Seite http://developer.apple.com/submission/iphone/ screenshot.php als TIFF-Datei herunterladen und in einem Bildbearbeitungsprogramm mit Ihrem erstellten Screenshot verbinden. Somit wird sichergestellt, dass der Web-AppKatalog aufgeräumt aussieht und alle Screenshots im einheitlichen Design dargestellt werden. Haben Sie alles erledigt, können Sie über Submit Ihre Webanwendung an Apple übermitteln.
4.1.1
Andere Vertriebsmöglichkeiten für Web Apps
Mobile Webanwendungen sind technisch nichts anderes als Webseiten, und daher empfiehlt sich auch die Beantragung zur Aufnahme in die großen Suchmaschinen dieser Welt. Falls Sie bereits eine Webseite betreiben und eine Web App als Ergänzung für Ihre
338
Kapitel 4 – Webanwendungen und native Apps veröffentlichen
iPhone- und Android-Besucher erstellen, ist der effektivste Weg, Benutzer für die mobile Seite zu finden, eine Umleitung auf Ihrer Webseite einzubauen. Somit erhält jeder, der Ihre normale Webseite mit einem geeigneten mobilen Gerät ansurft, automatisch die optimierte Webanwendung. Solche Umleitungen sind schnell eingerichtet und wurden am Anfang des Buchs beschrieben.
4.2
iTunes App Store
Wenn Sie mit PhoneGap Ihre iPhone-App fertiggestellt haben, wird es Zeit, sie im iTunes App Store zu veröffentlichen und gegebenenfalls dort auch die Anwendung zu verkaufen. Dazu müssen Sie Mitglied im iPhone Developer-Programm sein. Die Mitgliedschaft kostet für Einzelpersonen, die ihre iPhone-App unter ihrem eigenen, persönlichen Namen vertreiben möchten, 99 US-Dollar und für Firmen 299 US-Dollar. Nähere Informationen dazu finden Sie im Abschnitt 3.2.1 »Entwicklungsumgebung für iOS-Entwicklung einrichten«. Die App mit Xcode für den App Store vorbereiten Bislang haben Sie Ihre Apps, die wir mit Xcode erstellt und auf den Geräten getestet haben, nur für den eigenen Entwicklungsbedarf kreiert. Die bislang erstellten Dateien können Sie nicht zum Vertrieb über den iTunes App Store verwenden, da sie nur mit einem Development Profile (Entwicklungsprofil) versehen wurden und nicht mit einem Distribution Profile. 1. Um ein Distribution Profile zu erhalten, benötigen Sie ein Vertriebszertifikat. Sparen Sie sich aber die umständliche Erstellung über die Schlüsselbundverwaltung. Gehen Sie in Xcode in das Menü Window und rufen Sie dort den Organizer auf. Klicken Sie hier auf die bereits bekannte Ansicht Provisioning Profiles.
Bild 4.3: Distribution Profile im Organizer erstellen.
4.2 iTunes App Store
339
2. Stellen Sie sicher, dass Automatic Device Provisioning markiert ist, und klicken Sie dann auf Refresh. Sie werden danach aufgefordert, Ihre Apple ID und Ihr Passwort direkt in Xcode einzugeben. Ist das geschehen und haben Sie Submit Request angeklickt, wird Ihnen kurz gemeldet, dass Ihre Anfrage begutachtet wird. In der Regel dauert dieser Prozess nur wenige Minuten, wenn nicht gar Sekunden. 3. Jetzt geht es wieder zurück in den Browser: Ein Distribution Profile erhalten Sie auch über das iPhone Provisioning Portal – http://developer.apple.com/iphone/manage/ overview – mit einem Klick auf Provisioning in der linken Navigationsspalte. Dort sehen Sie unter Development Ihre Entwicklungsprofile aufgelistet. Navigieren Sie dann zu Distribution und erstellen Sie dort über New Profile ein neues Vertriebsprofil. 4. Im darauffolgenden Bildschirm wählen Sie dann die Option App Store als Vertriebsmethode aus und geben dem Profil einen verständlichen Namen.
Bild 4.4: Festlegen der Distributionsmethode und Angabe eines Profilnamens.
Wozu ist das Ad-hoc-Zertfikat gut? Für den Vertrieb im App Store benötigen Sie ein App Store Distribution-Profil. Wir empfehlen jedoch, vorher Ihre Anwendung gegen ein »Ad-hoc-Profil« zu testen. Ein Ad-hoc-Profil erlaubt Ihnen, Ihre App noch einmal auf diversen physischen Geräten als Release-Kandidat zu testen und sicherzustellen, dass darin keine Fehler enthalten sind. Sie können dabei sogar fremde Geräte von Betatestern provisionieren lassen, nachdem diese im Provisioning-Portal unter Devices eingetragen wurden und Sie den Betatestern nicht nur die kompilierte App-Datei, sondern auch das generierte Ad-hoc-Profil geschickt haben.
340
Kapitel 4 – Webanwendungen und native Apps veröffentlichen
5. Unter Distribution Certificate sollte jetzt das von Xcode aus beantragte Zertifikat stehen, das eine Gültigkeitsdauer von einem Jahr besitzt. Falls Sie dort kein Zertifikat sehen, können Sie den Status Ihrer Zertifikatsanfrage durch einen Klick auf Certificates in der linken Spalte und einen anschließenden Klick auf Distribution überprüfen. Sehen Sie auf der Zertifikatsseite die Meldung Pending, wird Ihre Anfrage noch bearbeitet. Sehen Sie dort kein Zertifikat, befolgen Sie bitte die Schritte, die im Abschnitt zum Erstellen eines iPhone Distribution Profile aufgeführt sind. 6. Haben Sie alle Angaben gemacht und auf Submit geklickt, werden Sie wieder ein paar Minuten warten müssen, da Ihr Distributionsprofil nicht sofort ausgestellt wird. Laden Sie nach ein paar Augenblicken die Seite neu: Ein Download-Button sollte dann neben dem Distribution Provisioning Profile erschienen sein:
Bild 4.5: Status Active: Der Download-Button erscheint neben der App.
7. Speichern Sie die Datei mit der Endung .mobileprovision auf Ihrem Mac und ziehen Sie das Dateisymbol über das Symbol von Xcode. Jetzt wird wieder das OrganizerFenster in der Provisioning Profiles-Ansicht geöffnet, und Sie sollten hier nun die gerade erstellte und heruntergeladene Provisionsdatei aufgelistet sehen.
4.2 iTunes App Store
341
Bild 4.6: Anzeige der eben erstellten Provisionsdatei.
Da sich ab sofort das Profil in Xcode befindet, können Sie nun damit beginnen, die für den Vertrieb gültige Version Ihrer App zu bauen. Vorher sind aber noch ein paar Einstellungen nötig. 8. Um zu den Projekteinstellungen zu gelangen, wählen Sie aus dem Menü Project den Unterpunkt Project Settings. In dem darauf erscheinenden Fenster klicken Sie in den Build-Bereich und wählen aus dem Configuration-Drop-down-Menü die Option Release aus. Bislang haben Sie im Debug-Modus zum Programmieren gearbeitet – jetzt schalten Sie in den Release-Modus um. Suchen Sie nun in der Settings-Liste den Bereich Code Signing und wählen Sie dort unter Code Signing Idendity Ihr vorhin erstelltes Distributionsprofil aus:
342
Kapitel 4 – Webanwendungen und native Apps veröffentlichen
Bild 4.7: Erstelltes Distributionsprofil auswählen.
9. Als nächsten Schritt müssen Sie in der Xcode-Hauptansicht in der Spalte Groups & Files den Namen Ihrer App unter Targets markieren, über das Kontextmenü den Punkt Get Info aufrufen und im erscheinenden Target-Infofenster auf Properties klicken.
Bild 4.8: Aufruf der Properties.
4.2 iTunes App Store
343
10. Im Provisioning-Portal haben Sie theoretisch zwei Möglichkeiten, eine App ID zu definieren, einmal über den von uns benutzten Assistenten und zum anderen über eine spezielle Unterseite, die durch die Navigationsleiste im Provisioning-Portal über App IDs zu erreichen ist. Der Assistent generiert sogenannte Wildcard App IDs, bei denen Sie keine Möglichkeit haben, einen Bundle Identifier mit anzugeben. In unserem Beispiel hatten wir von Apple eine ID in folgendem Format bekommen: PQT793FQHZ.*. Hätten wir auf der Provisioning-Portal-Seite für eine App ID einen Bundle Identifier definiert, müssten wir diesen jetzt im Target-Infofenster unter Identifier eingeben. Bei einer Wildcard Apple ID wie unserer haben wir jetzt die Möglichkeit, diesen Identifier zu wählen, der in folgendem Format angegeben wird: com.firmenname.appname
Für das Beispiel verwenden wir: com.spiering.automarkt
11. Schließen Sie das Einstellungsfenster und geben Sie Xcode ein paar Sekunden Zeit, bis auch die Info.plist-Datei mit dieser neuen ID aktualisiert wurde. 12. Zurück in der Xcode-Hauptansicht, erstellen Sie jetzt Ihre finale Version. Dazu wählen Sie aus dem linken oberen Menü Device und Release aus. Bevor Sie zum vielleicht letzten Mal auf Build and Run klicken, empfiehlt es sich, das Projekt noch einmal über Clean All Targets zu säubern. Ab dann gilt es: Klicken Sie auf Build and Run und bestätigen Sie den Zugriff auf die Schlüsselbundverwaltung. Anschließend finden Sie im Ordner Products unter Groups & Files auf der linken Seite des XcodeFensters eine frische, neue Datei mit der Dateiendung .app. Das ist Ihre Vertriebsdatei, die Sie jetzt innerhalb des Finders noch als ZIP-Datei komprimieren sollten.
Bild 4.9: Die fertige Vertriebsdatei.
Die fertige ZIP-Datei werden wir in wenigen Augenblicken in den iTunes App Store laden.
344
Kapitel 4 – Webanwendungen und native Apps veröffentlichen
iTunes Connect Das eigentliche Veröffentlichen Ihrer App erfolgt nicht über das iPhone DevCenter, sondern über die Webseite iTunes Connect: http://itunesconnect.apple.com. 1. Auch hier identifizieren Sie sich über die Apple ID, die Sie auch für den Zugang zu den Apple Developer-Diensten benutzen. Stimmen Sie beim ersten Aufruf der Seite den iTunes Connect-Geschäftsbedingungen zu.
Bild 4.10: Aufruf der Website iTunes Connect.
iTunes Connect ist die zentrale Seite, wenn es um das Verwalten und Verkaufen Ihrer Apps geht. Hier können Sie neue Apps zum Vertrieb bereitstellen, die Beschreibungen und Screenshots für den App Store ändern, monatliche Statistiken der Downloads und Verkäufe sehen oder weitere Benutzer anlegen, die ebenfalls Zugriff auf Ihre iTunes Connect-Seite erhalten. 2. Um eine neue App in den Store zu stellen, klicken Sie von der Startseite aus auf Manage Your Applications. Danach sehen Sie eine Übersicht all Ihrer Apps, die entweder in das System gestellt wurden, noch auf die Apple-Freigabe warten oder bereits im App Store zum Verkauf bzw. zur Installation verfügbar sind. Da Sie noch keine Apps in Apples »Laden« haben, ist diese Ansicht für Sie bisher leer. Für die weitere Vorbereitung empfehlen wir Ihnen, die folgenden Beschreibungen und Dateien zur Hand zu haben:
4.2 iTunes App Store
345
•
Eine ausführliche Beschreibung Ihrer App, die im App Store angezeigt wird. Verwenden Sie kurze, knackige Sätze am Anfang und versuchen Sie, die wichtigsten Punkte aufzuzählen. Sie haben dazu maximal 4.000 Zeichen.
•
Ein paar Schlüsselwörter, die Ihre App treffend beschreiben, aber zusammen mit Kommata nicht mehr als 100 Zeichen lang sein dürfen. Die Schlüsselwörter werden bei der App Store-Suche benutzt. Wählen Sie daher diese Schlüsselwörter sorgfältig aus, sie könnten darüber entscheiden, ob Ihre App im Store leicht oder schwer gefunden wird.
•
Das Programmsymbol Ihrer Anwendung – allerdings im Großformat von 512 x 512 Bildpunkten. Es wird im iTunes App Store auf dem Desktop innerhalb von iTunes und auf den von iTunes generierten Produktwebseiten verwendet.
•
iPhone oder iPod touch-Screenshots von Ihrer App. Diese müssen im PNG-, JPEG- oder TIFF-Format vorliegen und dürfen folgende Abmessungen in Bildpunkten haben: 320 x 480, 480 x 320, 480 x 300, 640 x 960 oder 960 x 640.
•
Falls Ihre App auch oder sogar nur auf dem iPad läuft, sollten bzw. müssen Sie auch dafür passende Screenshots Ihrer App erstellen. Es werden dabei die gleichen Formate wie für das iPhone akzeptiert, allerdings müssen die Screenshots folgende Größen haben: 768 x 1.024, 1.024 x 768, 748 x 1024 oder 1.004 x 768.
3. Zurück in iTunes Connect, werden Sie beim Anlegen einer neuen Anwendung die primäre Sprache Ihrer Anwendung angeben müssen. Anschließend gelangen Sie zu einem Bildschirm, in dem Sie den Namen Ihrer Anwendung noch einmal angeben müssen. Im zweiten Feld dieser Seite können Sie eine ID eingeben, die einzigartig für Ihre Anwendung ist und auch nicht mehr geändert werden kann. Diese ID ist nicht für den Benutzer sichtbar. Wir verwenden für unser Beispiel einfach OldtimerMarkt-001, da das die erste Version unserer Oldtimer-App ist.
Bild 4.11: Eingabe der App Information.
346
Kapitel 4 – Webanwendungen und native Apps veröffentlichen
Im nächsten Feld wählen Sie Ihre Wildcard App ID aus und geben im Feld Bundle ID Suffix den String ein, den Sie vor dem finalen Erstellen der App definiert haben: com.spiering.automarkt
4. Im nächsten Fenster legen Sie fest, ab wann Ihre App im App Store verfügbar sein soll. Machen Sie sich hier keine Illusionen: Auch wenn Sie den aktuellen Tag angeben, wird die App mit Sicherheit nicht binnen Minuten erscheinen. Apple muss die App immer noch überprüfen und dann gegebenenfalls freischalten. Falls Sie aber die App an einem bestimmten Tag veröffentlichen wollen, der noch in etwas fernerer Zukunft liegt, können Sie diese Angabe hier vornehmen. Wenn Sie die App so schnell wie möglich im App Store sehen möchten, nehmen Sie einfach das aktuelle Datum. 5. Da Sie Ihre App nicht verkaufen wollen, wählen Sie unter Price Tier (Preisstufe) den Punkt Free. Sollten Sie planen, für Ihre App Geld zu verlangen, müssen Sie hier die Preisstufe auswählen. Ihnen stehen dafür 85 Stufen zur Verfügung: Tier 1 bezeichnet die kostengünstigen Apps, die es für 79 Euro-Cent (Ihr Gewinn ist dann 48 EuroCent) oder 99 US-Cent zu kaufen gibt. Tier 85 ist demnach die Preisstufe für die teuersten Apps. Der Verkaufspreis würde im App Store dann bei 799 Euro bzw. 999 US-Dollar liegen. Sobald Sie auf der Seite eine Preisstufe auswählen, können Sie über See Pricing Matrix die einzelnen Preisstufen und deren Verkaufspreise und Gewinnausschüttung pro Währungsbereich sehen. Falls Sie Ihre App nicht in allen Ländern vertreiben können oder wollen, lässt sich auf dieser Seite der Vertrieb auch auf einzelne Länder beschränken. 6. Auf der nächsten Seite geben Sie neben der Versionsnummer auch die maximal 4.000 Zeichen lange Beschreibung, einige Schlüsselwörter für die App Store-Suche und noch ein paar weitere Informationen an. Weiter unten auf der Seite legen Sie fest, ob Ihre App bestimmte Inhalte enthält oder bestimmter Natur ist. Dadurch wird entschieden, wie alt beispielsweise ein iTunes-Kunde sein muss, um die App herunterladen oder kaufen zu können. Am Ende der Seite finden Sie noch die Uploadlinks, um nicht nur das große 512-x-512-Bild für iTunes hochzuladen, sondern auch um die iPhone-, iPod- und iPad-Screenshots an Apple zu übermitteln. 7. Haben Sie auch diesen Bildschirm hinter sich gebracht, erhalten Sie noch einmal eine Übersicht und müssen dann – wieder einen Bildschirm weiter – angeben, ob Ihre App irgendeine Art von Verschlüsselungstechnologie (Encryption) enthält. 8. Jetzt kommen wir zum letzten Punkt: dem Hochladen der als ZIP verpackten APPDatei. Dazu starten Sie das Programm App Loader. Es wurde bereits zusammen mit dem iOS SDK installiert und befindet sich unter /Developer/Applications/Utilities/ Application Loader.app. Nach dem Programmstart melden Sie sich wieder mit Ihrer Apple ID und Ihrem Passwort an und sehen kurze Zeit später in einem Auswahlmenü die gerade in iTunes Connect angelegte App:
4.3 Android Market
347
Bild 4.12: Auswahl der hochzuladenden Applikation.
9. Anschließend bestätigen Sie, dass Sie Ihre App auch unter iOS 4 getestet haben und nun die ZIP-Datei auswählen und an Apple schicken. Der App Loader wird Ihnen sofortiges Feedback geben, falls etwas mit Ihrem App-Paket nicht stimmt. Anderenfalls wird die App zu Apple gesendet, und Sie erhalten eine Bestätigung.
Bild 4.13: Die Bestätigung von Apple.
10. Auch in iTunes Connect können Sie unter Manage Your Applications sehen, dass Ihre App jetzt auf das finale Urteil von Apple wartet. In der Zwischenzeit können Sie für Ihre App über View Details und Manage Localizations wahlweise noch Beschreibungen in mehreren Sprachen hinzufügen, falls Ihre App mehrsprachig ist.
4.3
Android Market
Wenn Sie mit Ihrer Android-App glücklich und zufrieden sind, heißt es hier ebenfalls: raus damit in die Welt und in den Android Market. Im Android Market können sich Android-Benutzer wie im iTunes App Store Programme auf Ihr Gerät installieren und – in zahlreichen Ländern – auch käuflich erwerben.
348
Kapitel 4 – Webanwendungen und native Apps veröffentlichen
Bis wir unsere Android-App aber in den Android Market hochladen können, müssen wir erst eine finale Vertriebsversion erstellen. Dazu verwenden wir natürlich Eclipse und bearbeiten die Einstellungen in der Datei AndroidManifest.xml. 1. Als Erstes sollten Sie im Manifest-Bereich überprüfen, ob Sie die richtige Versionsnummer und den richtigen Versionscode definiert haben. Diese Angaben sind im Android Market sichtbar und können am oberen Rand unter den Manifest General Attributes eingestellt werden.
Bild 4.14: Versionscheck durchführen.
2. Als Nächstes navigieren Sie in den Application-Bereich. Dort finden Sie auf der rechten Seite die Einstellung, ob Ihre Anwendung Debuggable sein soll oder nicht. Momentan müsste das noch auf true gesetzt sein, ändern Sie diese Einstellung nun auf false. Der zur Fehlersuche und -analyse bestimmte Programmcode, der während des Programmierens nützlich ist, braucht sich in unserer fertigen App nicht zu befinden. Navigieren Sie jetzt zum nächsten Bereich Permissions.
4.3 Android Market
349
Bild 4.15: Prüfen, ob die Anwendung Debuggable sein soll.
Hier sehen Sie eine ganze Menge verschiedener Berechtigungen aufgelistet, die die Anwendung besitzen soll. Falls Sie keine der nativen Systemfunktionen per JavaScript in Ihrer Anwendung verwenden, können Sie alle Berechtigungen löschen bis auf: READ PHONE STATE INTERNET
Sprechen Sie die Kamera von Ihrer App aus an, benötigen Sie zusätzlich: CAMERA
Falls Sie den Vibrationsalarm benutzen, benötigen Sie: VIBRATE
Und wenn Sie Geopositionsfunktionen nutzen, brauchen Sie folgende Berechtigungen: ACCESS COARSE LOCATION ACCESS FINE LOCATION ACCESS LOCATION EXTRA COMMANDS
3. Haben Sie bereits selbst Anwendungen vom Android Market heruntergeladen und installiert, werden Sie den Dialogbildschirm kennen, in dem der Benutzer darauf hingewiesen wird, welche Systemfunktionen die Anwendung benutzt. Wenn Sie die überflüssigen Zugriffsberechtigungen hier nicht entfernen, wird der Benutzer vor der Installation Ihrer App an insgesamt 14 Punkten gewarnt. Diese kann er zwar alle auf einmal bestätigen, allerdings sieht es komisch aus, wenn der Benutzer den Kamerazugriff bestätigen muss, obwohl Ihre Anwendung möglicherweise die Kamerafunktion gar nicht eingebaut hat.
350
Kapitel 4 – Webanwendungen und native Apps veröffentlichen
Sichern Sie die Datei AndroidManifest.xml und öffnen Sie die Datei strings.xml im Verzeichnis res unter values.
Bild 4.16: Sind Sie mit Ihrem App-Namen noch nicht zufrieden, können Sie ihn hier ändern.
4. Wir ändern den App-Namen von »oldtimermarkt« auf »Oldtimer«, da der alte Name selbst auf Geräten mit hochauflösenden Bildschirmen zu lang war und einen Zeilenumbruch verursacht hatte. Speichern Sie jetzt auch die Datei strings.xml ab. 5. Öffnen Sie nun die AndroidManifest.xml-Ansicht. Im Manifest-Bereich finden Sie relativ weit unten auf der Seite den Link Use the Export Wizard unter Exporting. Das ist der bequemste und schnellste Weg, eine Android-Anwendungsdatei für die Veröffentlichung zu generieren. 6. Ist der Assistent gestartet, wählen Sie das Projekt aus, das Sie signieren und exportieren möchten. Da es sich um unser aktuelles Android-Projekt handelt, können Sie das vorgeschlagene Projekt einfach mit Klick auf Next akzeptieren. Warnung des Export-Assistenten Der Export-Assistent teilt Ihnen an dieser Stelle auch mit, ob sich noch offensichtliche Fehler im Code befinden. Nehmen Sie die hier erscheinenden Warnungen ernst und beheben Sie die Fehler, bevor Sie mit dem Exportieren fortfahren. 7. Als Nächstes müssen Sie einen sogenannten Keystore anlegen. Hiermit generieren Sie eine Datei, in der ein Schlüssel gespeichert wird, dessen Passwort nur Sie kennen und mit dem die Anwendung signiert wird.
4.3 Android Market
351
Bild 4.17: Einen Keystore anlegen.
8. Vergeben Sie einen frei gewählten Dateinamen und wählen Sie ein Verzeichnis aus, in das die Schlüsseldatei abgelegt wird. Suchen Sie sich dann ein Passwort aus und geben Sie es ein. 9. Jetzt geben Sie Ihrem Schlüssel einen Aliasnamen. Da Sie diesen Schlüssel für all Ihre Android-Anwendungen benutzen können, empfiehlt es sich, ihn unabhängig vom App-Namen zu wählen. Nach der Angabe des Passworts müssen Sie noch festlegen, wie lange der Schlüssel gültig sein soll (Validity). Die Angabe erfolgt in Jahren – und seien Sie dabei nicht zögerlich: Ein Zeitraum von 25 Jahren wird empfohlen.
Bild 4.18: Festlegen der Exporteinstellungen.
Wichtig! Vergessen Sie auf keinen Fall die verwendeten Passwörter, da sonst keine Möglichkeit mehr besteht, die App im Android Market zu aktualisieren oder zu verändern. 10. Im letzten Schritt werden Sie aufgefordert, einen Speicherplatz für Ihre AndroidPaketdatei (APK) zu definieren. Diese APK-Datei ist Ihre Android-Programmdatei, die Sie auch in den Android Market hochladen müssen:
352
Kapitel 4 – Webanwendungen und native Apps veröffentlichen
Bild 4.19: Den Speicherplatz für die App festlegen.
Jetzt wird die APK-Datei mit einem Klick auf Finish in dem von Ihnen angegebenen Verzeichnis erstellt.
4.3.1
App an Betatester schicken oder außerhalb des Android Market vertreiben
Sie müssen Ihre App zum Vertrieb nicht unbedingt in den Android Market stellen. Suchen Sie viele Abnehmer oder Käufer für Ihre Software, ist sicher der Android Market die beste Möglichkeit, doch wenn Sie Ihre Software erst einmal von Betatestern gründlich untersuchen lassen wollen, ist auch das relativ einfach möglich. Das Einzige, was Sie tun müssen, ist, Ihre signierte APK-Datei auf einen Webserver zu laden und Ihren Kunden oder Benutzern einen Downloadlink anzubieten. Alternativ können Sie die APK-Datei per E-Mail verschicken, dann müssten Ihre Benutzer allerdings die E-Mail direkt auf dem Gerät öffnen oder die APK-Datei von der E-Mail auf die SD-Karte des Android-Geräts schieben und von dort mit einem Installationsprogramm installieren. Ein empfehlenswertes und zudem noch kostenloses Installationsprogramm ist Apk Manager. Sie sehen – der Weg über einen Webserver-Download ist der einfachere. Mit einer Hürde werden aber alle zukünftigen Benutzer Ihres Programms zu kämpfen haben, sofern sie die App nicht aus dem Android Market beziehen: Wenn die Benutzer ihre Einstellungen nicht schon vorher entsprechend gesetzt haben, werden sie aufgefordert, folgende Einstellungen vorzunehmen: Der Benutzer muss im Einstellungsprogramm unter dem Punkt Anwendungen die Installation von Apps mit Unbekannter Herkunft zulassen. Glücklicherweise braucht der Benutzer nicht erst das Einstellungsprogramm selbst aufzurufen, stattdessen wird er direkt vom Installationsdialog dorthin geführt. Eine hoffentlich nicht zu abschreckende Meldung: Selbst wenn Sie wollten, hätten Sie große Schwierigkeiten, eine PhoneGap Android-App wirklich »gefährlich« für das Telefon zu gestalten.
4.3 Android Market
353
Bild 4.20: Apps unbekannter Herkunft zulassen.
4.3.2
App im Android Market veröffentlichen
Während Sie das Android SDK und die benötigten Entwicklungsprogramme ohne Registrierung und Kosten herunterladen konnten, müssen Sie sich, um eine App im Android Market zu veröffentlichen, als Android-Entwickler registrieren und eine kleine Aufnahmegebühr von 25 US-Dollar bezahlen. 1. Die Anmeldung erfolgt über die Seite http://market.android.com/publish/signup, auf der Sie sich mit Ihrem Google-Account anmelden. Anschließend werden Sie aufgefordert, ein paar Daten von sich zu hinterlegen. Wichtig ist hier das Feld Developer Name. In diesem Feld legen Sie fest, unter welchen Namen Ihre Apps im Android Market verkauft werden. Tragen Sie entweder Ihren echten Namen oder Ihren Firmennamen ein.
Bild 4.21: Anmeldung im Android Market.
354
Kapitel 4 – Webanwendungen und native Apps veröffentlichen
2. Im nächsten Schritt müssen Sie dem Android Market Developer Distribution Agreement – also der Vereinbarung zum Vertrieb – zustimmen und den Betrag von 25 US-Dollar über Google Checkout entrichten. Bei Google Checkout können Sie mit allen gängigen Kreditkarten bezahlen. 3. Haben Sie das erfolgreich hinter sich gebracht, befinden Sie sich jetzt auf Ihrer Android Market-Seite. Von hier aus können Sie über Upload Application Ihre erste Android App veröffentlichen.
4.3.3
App im Android Market verkaufen
Wie bei iTunes können Sie Ihre Software im Android Market nicht nur zum Download anbieten, sondern auch verkaufen. Auch Google setzt eine Transaktionsgebühr von 30 % vom Verkaufspreis für einen erfolgreichen Verkauf an. Sie erhalten pro Verkauf also 70 % des Verkaufspreises. 1. Damit das Geld auch bei Ihnen ankommt, müssen Sie von Ihrer Android MarketSeite aus Setup Merchant Account auswählen und, je nachdem, in welchem Land Sie sich befinden, bestimmte Bank- oder Steuerinformationen angeben. Es sei darauf hingewiesen, dass der Android Market zwar in fast jedem Land verfügbar ist, jedoch der Verkauf von Software bislang nur in einigen Ländern ermöglicht wird. Lesezeichen http://bit.ly/LUNA2 Eine genaue Übersicht darüber, in welchen Ländern der Verkauf von Software möglich ist und in welchen Ländern nur Freeware angeboten werden kann, finden Sie hier.
2. Nach dem Klick auf Upload Application landen Sie auf einer Seite, auf der Sie nicht nur Ihre signierte APK-Datei hochladen, sondern auch diverse Angaben zu Ihrer App machen können, die dann letztendlich im Android Market erscheinen. Hier noch einige Tipps: Sie können pro Anwendung zwei Screenshots hochladen. Die Screenshots müssen entweder im PNG- oder im JPG-Format vorliegen und dürfen die Abmessungen 320 x 480 Bildpunkte oder 480 x 854 Bildpunkte haben. Screenshots werden im Android Market immer im Hochformat angezeigt. Auch wenn Ihre Anwendung oder Ihr Spiel nur im Querformat läuft: Drehen Sie entweder den Screenshot ins Hochformat oder verwenden Sie zwei querformatige Screenshots übereinander auf einer hochformatigen Grafik. Als Nächstes können Sie eine Werbegrafik hochladen. Diese Werbegrafik wird unter Umständen im Android Market verwendet, wenn Google sie gut findet und bewerben möchte. Das Format der Grafik erinnert an einen Banner: 180 x 120 Bildpunkte. Beispiele dieser Werbegrafiken finden Sie beim Aufruf des Android Market von einem Telefon auf der Startseite.
4.3 Android Market
355
Bild 4.22: Upload einer neuen Applikation.
3. Ihre Anwendung kann im Android Market unterschiedliche Namen pro Sprache besitzen. Um eine weitere Sprache hinzuzufügen, klicken Sie einfach auf Add Language. Der Titel darf pro Sprache 30 Zeichen besitzen. Wir empfehlen maximal 16 Zeichen, da sonst nicht der volle Name in der Listenansicht innerhalb des Android Market angezeigt wird. Als Nächstes können Sie eine Beschreibung Ihres Produkts angeben. Die App-Beschreibungen im Android Market sind wesentlich kürzer als bei iTunes. Versuchen Sie, Ihr Produkt kurz und präzise mit maximal 325 Zeichen zu beschreiben. Falls Google Ihre Anwendung oder Ihr Spiel mag und sich entschließt, es zu bewerben, würde der Promotext neben der oben hochgeladenen Promografik angezeigt. Die Platzierung sehen Sie, wenn Sie im Android Market auf eine der Kategorien klicken und sich die Listenansicht für beispielsweise Spiele ansehen. Der Promotext darf maximal 80 Zeichen lang sein und kann nur angegeben werden, wenn Sie auch eine Promografik erstellt und hochgeladen haben.
356
Kapitel 4 – Webanwendungen und native Apps veröffentlichen
4. Geben Sie dann noch an, ob es sich bei Ihrer App um eine Anwendung oder ein Spiel handelt und welcher Kategorie Sie es zuordnen möchten. Geben Sie Ihre Android App nur gegen Bezahlung ab, können Sie jetzt den Preis angeben. Ist ein Gratisangebot eher Ihr Ding, wählen Sie unter Price einfach Free. Eine als kostenlos eingestellte Anwendung kann später nicht mehr mit einem Preis versehen werden. In diesem Fall müssten Sie ein Update mit einer neuen, signierten APK-Datei durchführen. 5. Unter Copy Protection entscheiden Sie, ob Sie Ihre Anwendung mit einem Kopierschutz versehen möchten oder nicht. Nehmen Sie den Kopierschutz, ist es nicht mehr so einfach, die Anwendung nach dem Herunterladen auf eine Speicherkarte zu kopieren und in einem anderen Telefon zum Laufen zu bringen. Wie jeder Kopierschutz ist er nicht 100%ig sicher und daher nur sinnvoll, wenn Sie Ihre Anwendung verkaufen. Kopiergeschützte Programme oder Spiele benötigen auch einen größeren Speicherbedarf bei der Installation. Eine weitere Einschränkung ist, dass Apps mit Kopierschutz nicht auf Android-Entwicklertelefonen installiert werden können. Falls Sie Ihr Telefon ganz normal im Handel gekauft haben, sind Sie davon nicht betroffen. Nur Telefone, die direkt über das Android-Entwicklerprogramm gekauft wurden, erlauben keine Installation von kopiergeschützten Programmen. Wenn Sie Ihre App in allen Ländern vertreiben wollen, in denen der Android Market verfügbar ist und in Zukunft auch noch verfügbar sein wird, lassen Sie das Häkchen bei All locations gesetzt. Sobald Sie es entfernen, sehen Sie eine Länderliste, über die Sie gezielt den Vertrieb in bestimmte Länder festlegen können. 6. Ganz zum Schluss müssen Sie den Android Content-Richtlinien zustimmen und somit garantieren, dass Sie dem Android Market unbedenkliche Inhalte hinzufügen. Abschließend werden Sie noch gefragt, ob Sie Ihre Software ohne Anwendung von nicht zugelassener Verschlüsselungstechnik erstellt haben. Ist dem so, sind Sie fertig und können mit Publish Ihre App in den Android Market schicken.
Bild 4.23: Die App ist im Android Market veröffentlicht.
Wenn Sie den iTunes App Store gewohnt sind, werden Sie vom Android Market in einer Hinsicht begeistert sein: Sie warten nicht tagelang auf das finales Urteil darüber, ob Ihre App angenommen wird oder nicht, sondern mit dem Anklicken von Publish befindet sich Ihre App bereits für alle Benutzer im Markt.
357
Stichwortverzeichnis Symbol. .htaccess-Datei 37 2-pass Encoding 140 A addColorStop 111 Ad-hoc-Zertifikat 339 Adressbuch 67 Adressbucheinträge 296 ADT 241 Android 5, 243 Android Market 347, 354 Android SDK 243 Android, Anwendungen 13, 319 Kameraanwendungen 332 Android-Grafiken 330 AndroidManifest.xml 326 Animationen 57, 59, 101 Anordnung 116 Anwendungsdesign, mobil 22 APIs, neue 87 App-Icon 79 Apple iOS 5 Apple Web Apps-Katalog 335 Apple-Entwicklerprogramm 243 apple-Theme 55 Application Prototyping 23 ApplicationCache-API 231 Apps veröffentlichen 335 arc 98 article 85 aside 85 audio 86 Audio 122
Audiowiedergabe 123 autocapitalize 89 autocorrect 88 autoplay 130
B beginPath 96 Beispielcode 16 Betatester 352 Bewegungssensoren 311 bezierCurveTo 99 Bilder 101 Bildschirmgröße 24 BlackBerry 5 Browser 13 Desktop 33 mobile 33 C Cache löschen 230 Cache-Manifest 231 Cache-Manifestdatei 227 canvas 86 Canvas, zeichnen 93 Canvas-API 108 canvas-Element 91 Character-Encoding 85 Checkbox 53, 65 Chrome 14 class 86 clip 96, 101 closePath 96 Cloudmade 184 Container 56, 58 contenteditable 87 controls 130 coords 161
CSS 7, 41, 83 CSS-Farbwert 107
D Database-API 206 Datenbank-Queries 212 Design, iPhone-typisch 24 Designprinzipien 21 destination height 103 destination width 103 details 86 Diagramme 117 dir 86 div-Container 56 doctype 84, 85 Download, Beispiele 16 draggable 87 draw 101 drawImage 101, 103 Dynamische Inhalte 66 E Eclipse 322 email 88 E-Mails versenden 69 Entwicklungsumgebung 241 Android 243 iOS 241 Error-Callbacks 166 F Facebook, Startbildschirm 78 Fehlerbehandlung 135 Fehlercodes 137 figcaption 86 figure 86 fill 97
358
Stichwortverzeichnis
fillStyle 106 fillText 105 Firefogg 142 Voreinstellungen 144 VP8 147 WebM 147 Firefox 14 Erweiterung 40 Firebug 49 Flash 122 Flickr 122, 149 API-Anfragen 179 API-Schlüssel 179 georeferenzierte Fotos 176 Startbildschirm 78 flip 57 Flot 117 Flot-Toolkit 117 font 104 footer 85 Form-Element 53 Formulare 63 Fotobibliothek 304 Foursquare 185 Frameworks 41, 54 FTP-Programm 15 Füllfarbe 94 Füllmuster 112 Füllstil 106
G Geolocation 308 Geolocation-API 148 globalAlpha 107 Google Chrome 14, 49 Datenbanken 226 Google Maps Attribute 72 aufrufen 71 Google Maps-API 67, 155, 172 Gowalla 185
H H.264 128 header 85 height 81, 133 hgroup 85 hidden 87 Hochformat, Ansicht 81 Home-Bildschirm 76 HTML 7, 83 Telefonfunktionen 67 HTML 4 85 HTML5 7, 83, 122 offizielle Spezifikation 8 HTML5-Canvas 95 HTML5-Spezifikation 83 HTML-Schreibweise 83 HTTP-Header 34 HTTP-Protokoll 71 I icon 80 id 86 IDE 241 iframe 86 index.html 56 input 86, 89 Interface Builder 24 Internet Explorer 14 iOS SDK 24, 241 iOS-Anwendung 13 iPad 75, 122 iPad-Apps 314 iPhone 5, 75 iPhone Dev Center 243 iPhone OS, Tastaturbelegung 88 iPhone, Web Apps 75 iPod touch 75 iTunes 5 iTunes App Store 338 iWebKit 41
J JavaScript 7, 41, 83 JavaScript Plotting Library 117 JavaScript-API 137 jQTouch 41, 53 App-Icon 79 Fehler 66 Geolocation 185 Startup-Bildschirm 79 jqt-Theme 55 jQuery 53 K Kalender 68 Kamera 67, 304 Klassen 59 Kontaktformular 67 Kopfzeile 79 L Ladeanzeige 296 landscape 82 lang 86 Linien 97, 109 Linienstil 106 Listen 59 localStorage 189, 191 loop 131 M Maemo 5 mailto-Protokoll 69 measureText 104 MIME-Types 125 moveTo 97 Muster 110 N Native AndroidSystemfunktionen 330 Native Anwendungen 8, 239
Stichwortverzeichnis
Native iOS-Systemfunktionen 283 nav 85 navigator 77 New York Times 122 number 88
Routenplanung, Attribute 73
S Safari 13 Safari Web Inspector 47 sandbox 86 Schaltflächen 53 O Schatten 110, 113 Offline Web Applications 227 SDK 241 OGG Theora 142 seamless 86 OGG Vorbis 142 sessionStorage 189, 190 One-Shot-Positionsanfragen Sicherheit 149 156 SimpleGEO 184 Open Street Map 185 SMS-Anwendung 69 orientation 80 SMS-Nummer 69 Ortungsmethoden 160 spellcheck 87 output 86 SQL Injection 210 SQL-Basics 203 P SQLite-Datenbank 207 Pfade, kreisförmig 97 srcdoc 86 PhoneGap 239 Startup-Bildschirm 77, 79 Android-Anwendungen 319 startupScreen 80 entwickeln 259 Startzeit 78 Info.plist 273 statusBar 80 installieren 248 Storage-Event 199 iOS-Gerät testen 279 Strichstil 106 iPad-Apps 314 stroke 97 PHP 39 strokeStyle 106 placeholder 86 style 86 portrait 82 summary 86 Positionsbestimmung 155 Symbian 5 poster 131 T preload 135 tabindex 86 Privatsphäre 149 Tastaturbelegung 88 Q tel 88 quadraticCurveTo 99 Telefonfunktionen 67 Querformat, Ansicht 81 tel-Protokoll 68 QuickTime 127 Text 104 Texteditor 14 R Texteingabefeld 52 Radiobuttons 52, 65 Theora 127 Relationale Datenbank 203 time 86 Reverse Geocoding 172 Titanium 239
359
Transaktionen 206 Transformation 114 translate 101 Transparenz 107 Twitter-Updates zum Buch 7
U url 88 User-Agents 34, 40 V Verläufe 110 Veröffentlichen 335 video 86 Video 122, 126 Videocodecs 127 Videocontainer 126 Viewport 27 Vimeo 122 Vollbildmodus 77 VP8 128 W WatchPosition 167 Web Inspector 47 Web Inspector, Datenbanken 226 Web OS 5 Web SQL Database 202 Web Storage 188 Webanwendung 10 Webdesign, mobil 22 width 81, 133 Windows Phone 5 X Xcode 279 XML-Schreibweise 84 Y Yahoo! Place Finder 185 Yelp 185 YouTube 122
360
Stichwortverzeichnis
Z Zeichenoperationen 116 Zeichnen
Kreis 98 Kreisförmige Pfade 97 Kreisförmiger Abschnitt 99
Linien 97 Organische Formen 99 Rechteck 101
Markus Spiering / Sven Haiges
Aus dem Inhalt: • HTML5: Spezifikation und aktueller Stand • Im Fokus: mobile Designprinzipien • iPhone-typisches Design in der Praxis
HTML5-Apps für iPhone und Android iOS von Apple und Android von Google – wer Apps für das iPhone und andere Smartphones programmieren und damit in allen wichtigen App Stores Geld verdienen will, muss diese beiden Betriebssysteme beherrschen. Den Schlüssel dazu bieten HTML5, CSS und JavaScript, denn damit lassen sich mobile Apps plattformunabhängig entwickeln. Dieses Buch zeigt, wie Sie Anwendungen erstellen, die in den Browsern von iOS, Android und auch Blackberry OS ohne Anpassungen laufen, und wie Sie aus einer Web-App eine native Anwendung für den iTunes App Store und den Android Market bauen.
씰
씰
씰
Ein Programm für die wichtigsten Systeme Mit einer auf HTML5 basierenden Applikation stellen Sie sicher, dass Ihre Anwendung auf den wichtigsten mobilen Plattformen läuft. Gleichzeitig haben Sie die Option, daraus mit Frameworks wie PhoneGap eine native Anwendung für den iTunes App Store oder den Android Market zu bauen. Im Handumdrehen erstellen Sie Programme, die sich nicht nur in den App Stores verkaufen, sondern auch mit Funktionen bereichern lassen, die im Browser gar nicht zur Verfügung stehen: Die Bewegungssensoren, die Kamera, der Vibrationsalarm, der Kompass, das Adressbuch und vieles mehr lassen sich direkt per HTML-, CSS- und JavaScript-Code über wenige, einfache JavaScript-APIs steuern. Der richtige iPhone- und Android-Look für Ihre App Dieses Buch beschäftigt sich auch mit den neuen Funktionen und Möglichkeiten von HTML5 und zeigt diese eindrucksvoll und verständlich anhand vieler Beispiele im echten „iPhone- und Android-Look & Feel“. Last, but not least erfahren Sie, wie Sie Ihre frisch gebaute Anwendung dann auch im iTunes App Store und im Android Market verkaufen. Setzen Sie HTML5 perfekt ein Die Autoren Markus Spiering und Sven Haiges beschreiben eindrucksvoll, wie Sie HTML5 in der mobilen App-Entwicklung einsetzen und den gesamten Entwicklungsprozess von Anfang bis Ende verstehen. Hier bleiben keine Fragen offen.
• CSS- und JavaScript-Frameworks • HTML5 in der mobilen Webentwicklung • Das Canvas-Element: Formen, Pfade, Bilder, Text u. m.
• Audio- und Videoimplementierung • Aktuelle Benutzerposition durch die Geolocation-API ermitteln
• Positionsanfragen und Ortungsmethoden • Web Storage: sessionStorage und localStorage
• Web SQL-Datenbanken • Offline-Webanwendungen Webseiten ohne Internetanschluss
• Grundlagen der Cache-Manifestdatei • Die ApplicationCache-API • Native Anwendungen erstellen: SDKs, IDEs und ADTs
• iOS-Apps mit PhoneGap entwickeln • Android Apps mit PhoneGap entwickeln • Native Apps veröffentlichen • Apple Web Apps-Katalog • iTunes App Store und Android Market
Über die Autoren: Markus Spiering, Jahrgang 1977, ist verantwortlich für die mobile Produktpalette der weltweit größten Fotocommunity Flickr (www.flickr.com) in San Francisco, Kalifornien.
Sven Haiges, Jahrgang 1979, hat Bücher zu den Web-Frameworks Struts, JavaServer Faces (JSF) und Grails geschrieben, ist in München als freier AndroidBerater tätig.
Alle Beispieldateien auf www.buch.cd 30, EUR [D] ISBN 978-3-645-60052-1
Besuchen Sie unsere Website
www.franzis.de