PhoneGap Erstellen Sie einen Feed Reader - Anwendungslogik

Dies ist der zweite Teil der Serie Audero Feed Reader. In diesem Artikel werden wir in die Geschäftslogik unserer Anwendung eintauchen und zusätzliche Hintergrundinformationen zu den Plugins und der API für unser Projekt bereitstellen.


1. Plugin & API-Übersicht

Das Benachrichtigungs-Plugin

An mehreren Stellen innerhalb der Audero Feed Reader App verwenden wir die warnen() Methode des Benachrichtigungs-Plugins. Wie die Warnung angezeigt wird, hängt wirklich von der Plattform ab, auf der die App ausgeführt wird. Tatsächlich verwenden die meisten unterstützten Betriebssysteme ein systemeigenes Dialogfeld, aber andere, wie Bada 2.x, verwenden die klassischen Browser warnen() Funktion, die weniger anpassbar ist. Diese Methode akzeptiert bis zu vier Parameter:

  1. Botschaft: Eine Zeichenfolge, die die anzuzeigende Nachricht enthält.
  2. alertCallback: Ein Rückruf, der aufgerufen werden soll, wenn der Alert-Dialog geschlossen wird.
  3. Titel: Der Titel des Dialogs (der Standardwert ist "alert").
  4. buttonName: Der im Dialogfeld enthaltene Schaltflächentext (der Standardwert ist "OK").

Beachten Sie, dass Windows Phone 7 und 8 nicht über eine integrierte Browser-Warnung verfügen. Also, wenn Sie verwenden möchten Warnmeldung');, Sie müssen zuweisen window.alert = navigator.notification.alert.

Das InAppBrowser-Plugin

Im ersten Teil dieser Serie habe ich erwähnt, dass das Attribut ein interessanter Punkt auf der Credits-Seite ist target = "_ blank" auf die Links angewendet. In diesem Abschnitt wird erklärt, wie die openLinksInApp () Methode der Anwendung Klasse arbeitet.

Der InAppBrowser ist ein Webbrowser, der in Ihrer App angezeigt wird, wenn Sie den verwenden window.open Anruf. Wie ich im ersten Teil gesagt habe, gibt es ab Version 2.3.0 zwei neue Methoden: executeScript () und insertCSS (). Derzeit bietet dieses Plugin insgesamt fünf Methoden:

  • addEventListener (): Ermöglicht dem Benutzer, auf drei Ereignisse zu warten (Ladestart, Ladestopp, und Ausfahrt) und um eine Funktion anzuhängen, die ausgeführt wird, sobald diese Ereignisse ausgelöst werden.
  • removeEventListener (): Zum Entfernen eines zuvor angefügten Listeners.
  • schließen(): Wird verwendet, um das InAppBrowser-Fenster zu schließen.
  • executeScript (): Ermöglicht das Einfügen von JavaScript-Code in das InAppBrowser Fenster.
  • executeScript (): Ermöglicht das Einfügen von CSS-Code in das InAppBrowser Fenster.

Wenn Sie Cordova mehrere Monate nicht verwendet haben oder sich an Version 2.0.0 halten, werden Sie sich daran erinnern, dass standardmäßig externe Links in derselben Cordova-WebView geöffnet wurden, in der die Anwendung ausgeführt wurde. Sobald eine externe Seite aufgerufen wurde, wurde die zuletzt angezeigte Seite genau so angezeigt, wie sie vor dem Verlassen des Benutzers war. Ab dieser Version ist dies nicht mehr das Standardverhalten. Tatsächlich werden externe Links jetzt mit Cordova WebView geöffnet, wenn sich die URL in der Whitelist Ihrer App befindet. URLs, die sich nicht in Ihrer Positivliste befinden, werden mit dem InAppBrowser-Plugin geöffnet (mehr dazu in der Dokumentation). Was bedeutet das praktisch? Wenn Sie die Links nicht ordnungsgemäß verwalten und die Benutzer Ihrer App auf einen Link klicken und dann zur Anwendung zurückkehren, gehen alle jQuery Mobile oder andere derartige Verbesserungen verloren. Dies geschieht, weil alle CSS- und JavaScript-Dateien nur auf der Hauptseite geladen werden und die nachfolgenden URLs mit AJAX (dem von jQuery Mobile übernommenen Standardsystem) geladen werden..

Das Update für dieses Problem ist in der implementiert openLinksInApp () Methode. Tatsächlich besteht die Lösung darin, die Klicks auf alle externen Links zu erfassen, indem Sie die Option target = "_ blank" Attribut, um das unerwünschte Standardverhalten zu verhindern und die Links mit der window.open () Methode. Damit diese Lösung funktioniert, müssen Sie in der Konfigurationsdatei eine Whitelist festlegen.

Die Google Feed-API

Bevor wir über die Klassen der Audero Feed Reader, Wir müssen in die magische Welt der Google Feed API und der Google Feed JSON-Oberfläche eintauchen, da wir sie innerhalb des Kernfeatures unserer Anwendung verwenden. Wie ich im ersten Teil dieser Serie darauf hingewiesen habe, analysiert die Benutzeroberfläche einen RSS- oder ATOM-Feed und gibt ein einheitliches und einfach zu analysierendes JSON-Objekt zurück. Natürlich können wir dieses JSON-Objekt mithilfe von JavaScript problemlos verwalten.

Diese Schnittstelle unterstützt zwei Abfragetypen: Feed suchen und Feed laden. Beim ersten wird nach Feeds anhand der angegebenen Schlüsselwörter gesucht, während der zweite Feed anhand der angegebenen Feed-URL sucht. In unserer Anwendung verwenden wir nur die Funktion zum Laden von Feeds.

Jede Anfrage an dieses Google-API muss mindestens zwei Parameter senden: v und q. Ja, sie haben sehr kryptische Namen! Der erste Parameter, v, gibt die Versionsnummer des Protokolls an. Zum Zeitpunkt dieses Schreibens ist der einzig gültige Wert "1,0". Im zweiten Parameter, q, Wir übergeben die URL zum Analysieren. Darüber hinaus verwendet unsere Anwendung auch die num Parameter. Die Dokumentation Gibt die Anzahl der Einträge an, die aus dem mit q angegebenen Feed geladen werden sollen. Der Wert -1 gibt die maximal unterstützte Anzahl von Einträgen an, derzeit 100. Standardmäßig liefert der Lade-Feed vier Ergebnisse. Daher ist es unumgänglich, unsere Funktion zu implementieren, 10 Einträge standardmäßig zu laden und dann jedes Mal um weitere 10 zu erhöhen, wenn der Benutzer mehr anzeigen muss.

Nun, da Sie wissen, wie wir den Google-Dienst abfragen, ist es wichtig, das Ergebnis zu klären, das es liefert. Wenn die von uns angegebene URL korrekt war, finden wir die Einträge des Feeds im responseData.feed.entries Eigentum. Jeder Eintrag enthält viele Informationen, aber wir werden nur einige davon verwenden. Insbesondere drucken wir die folgenden Eigenschaften:

  • Titel: Der Titel des Eintrags.
  • Verknüpfung: Die URL für die HTML-Version des Eintrags.
  • Autor: Der Autor des Eintrags.
  • contentSnippet: Ein Ausschnitt aus weniger als 120 Zeichen des Inhaltsattributs. Das Snippet enthält keine HTML-Tags.

Die Details, die ich oben angegeben habe, sind für unsere Anwendung ausreichend. Wenn Sie mehr darüber erfahren möchten, werfen Sie einen Blick auf die Google Feed-Dokumentation.


2. Erstellen der Feedklasse

Dieser Abschnitt beschreibt das Futter Klasse und ihre Methoden, alle in der feed.js Datei. Wie ich bereits im vorherigen Teil darauf hingewiesen habe, speichern wir für jeden Feed nur zwei Felder: den Titel und die URL. Diese Klasse akzeptiert also diese beiden Datenpunkte als Parameter. Darin erstellen wir zwei private Immobilien: _db und _Tabellenname. Denken Sie daran, dass JavaScript keine Modifizierer für die Sichtbarkeit von Eigenschaften und Methoden enthält. Daher emulieren wir tatsächlich private Daten.

Die erste ist eine Abkürzung für die lokaler Speicher Eigentum der Fenster Objekt. Es wird verwendet, um auf die Methoden zuzugreifen, die vom Storage Plugin bereitgestellt werden, auf dem unsere App basiert, und mit dem wir die Feeds speichern. Die zweite ist eine Zeichenfolge, die den Namen des Schlüssels enthält, in dem die Daten gespeichert werden. Beim Abrufen der Speicherspezifikationen werden die Daten in einem Schlüsselwertformat gespeichert. Um unser Array von Feeds zu speichern, müssen wir es daher JSON-ify machen. Genau das ist unser sparen() Methode wird es tun. Auf dieselbe Weise müssen wir zum Abrufen der Daten eine JSON-Zeichenfolge analysieren, um sie in ein Objekt umzuwandeln. Diese Aufgabe wird durch die erledigt Belastung() Methode. Diese Methoden sind die einzigen beiden, die in der Klassendefinition enthalten sein müssen, da sie private Eigenschaften verwenden.

Der relative Abschnitt des feed.js Die Datei ist unten aufgeführt:

 function Feed (Name, URL) var _db = window.localStorage; var _tableName = 'feed'; this.name = name; this.url = url; this.save = Funktion (Feeds) _db.setItem (_tableName, JSON.stringify (Feeds)); ; this.load = function () return JSON.parse (_db.getItem (_tableName)); ; 

Um diese beiden einfachen Methoden werden wir eine Reihe anderer allgemeiner Methoden erstellen. Insbesondere werden wir einige Instanzmethoden wie z hinzufügen(), einen neuen Feed hinzufügen, löschen(), einen Feed löschen, und vergleichen mit(), So vergleichen Sie eine Feed-Instanz mit einem anderen Feed. Neben diesen entwickeln wir auch statische Methoden wie getFeeds () um alle Feeds aus dem Speicher abzurufen, getFeed () nur einen abrufen, und vergleichen Sie() um zwei Objekte zu vergleichen.

Die Vergleichsmethoden sind eine kleine Diskussion wert Wie Wir werden sie vergleichen. Ich werde die Beschreibung von überspringen vergleichen mit() weil es nichts anderes tut, als sein statisches Gegenstück zu nennen, vergleichen Sie(), das erledigt eigentlich die Arbeit. Darin testen wir zuerst, ob einer der angegebenen Werte null ist. Falls keine davon null ist, vergleichen wir lexikographisch ihren Namen und, falls sie gleich sind, ihre URL. Wie Sie später jedoch feststellen werden, zwingen wir den Benutzer, niemals zwei Feeds mit demselben Namen oder derselben URL zu haben.
Das vergleichen Sie() Diese Methode ist wichtig, da sie die Art und Weise definiert, auf die wir zwei Feeds vergleichen, und dies ist entscheidend, um festzulegen, wie die Feeds in der list-feeds.html Seite. In der Tat werden wir das native verwenden Sortieren() Array-Methode, die einen optionalen Parameter akzeptiert, eine Funktion, die die Sortierreihenfolge des Arrays basierend auf den Rückgabewerten definiert.

Der Code, der das, was ich beschrieben habe, implementiert, ist folgender:

 Feed.prototype.compareTo = Funktion (andere) return Feed.compare (this, other); ; Feed.compare = Funktion (Feed, Sonstiges) if (other == null) return 1;  if (feed == null) return -1;  var test = feed.name.localeCompare (other.name); return (test === 0)? feed.url.localeCompare (other.url): test; ;

Zusätzlich zu den bisher bekannten Methoden erstellen wir zwei Suchmethoden, mit denen wir einen bestimmten Feed suchen und löschen: Suche mit Name() und searchByUrl (). Die letzte Methode, die ich hervorheben möchte, ist getIndex (), und es ist der, mit dem der Index einer bestimmten Datei abgerufen wird.

Nun, da wir alle Details dieser Klasse aufgedeckt haben, kann ich den gesamten Quellcode der Datei auflisten:

 function Feed (Name, URL) var _db = window.localStorage; var _tableName = 'feed'; this.name = name; this.url = url; this.save = Funktion (Feeds) _db.setItem (_tableName, JSON.stringify (Feeds)); ; this.load = function () return JSON.parse (_db.getItem (_tableName)); ;  Feed.prototype.add = function () var index = Feed.getIndex (this); var feeds = Feed.getFeeds (); if (index === false) feeds.push (this);  else feeds [index] = this;  this.save (Feeds); ; Feed.prototype.delete = function () var index = Feed.getIndex (this); var feeds = Feed.getFeeds (); if (index! == false) feeds.splice (index, 1); this.save (Feeds);  Rückgabe von Feeds; ; Feed.prototype.compareTo = Funktion (andere) return Feed.compare (this, other); ; Feed.compare = Funktion (Feed, Sonstiges) if (other == null) return 1;  if (feed == null) return -1;  var test = feed.name.localeCompare (other.name); return (test === 0)? feed.url.localeCompare (other.url): test; ; Feed.getFeeds = function () var feeds = neuer Feed (). Load (); return (feeds === null)? [] : Einspeisungen; ; Feed.getFeed = Funktion (Feed) var index = Feed.getIndex (feed); if (index === false) return null;  var feed = Feed.getFeeds () [Index]; Neuen Feed zurückgeben (feed.name, feed.url); ; Feed.getIndex = Funktion (Feed) var feeds = Feed.getFeeds (); für (var i = 0; i < feeds.length; i++)  if (feed.compareTo(feeds[i]) === 0)  return i;   return false; ; Feed.deleteFeeds = function ()  new Feed().save([]); ; Feed.searchByName = function (name)  var feeds = Feed.getFeeds(); for (var i = 0; i < feeds.length; i++)  if (feeds[i].name === name)  return new Feed(feeds[i].name, feeds[i].url);   return false; ; Feed.searchByUrl = function (url)  var feeds = Feed.getFeeds(); for (var i = 0; i < feeds.length; i++)  if (feeds[i].url === url)  return new Feed(feeds[i].name, feeds[i].url);   return false; ;

3. Erstellen der Anwendungsklasse

Dieser Abschnitt behandelt die zweite und letzte Klasse des Projekts, Anwendung, enthalten in der application.js Datei. Ziel ist es, das Layout der Seiten zu initialisieren, Ereignisse an die Seitenelemente der App anzuhängen und die Futter Klasse zum Speichern, Laden und Abrufen von Feeds.

Diese Klasse ist so organisiert, dass der Einstiegspunkt in der initApplication () Methode. Es wird aufgerufen, sobald Cordova initialisiert wurde und die APIs bereit sind, zu handeln. Innerhalb dieser Methode fügen wir jeder Seiteninitialisierung einen bestimmten Handler hinzu, damit wir die Ereignisse verwalten können, die von ihren Widgets ausgelöst werden. Darin rufen wir auch an Application.openLinksInApp () aus zuvor diskutierten Gründen. Darüber hinaus erfassen wir zur Verbesserung der Benutzererfahrung jedes Mal die physische Zurück-Taste (sofern vorhanden), um den Benutzer auf die Startseite unserer App umzuleiten.

Die Kernfunktion unserer Anwendung ist initShowFeedPage () weil es die Google Feed JSON-Schnittstelle verwendet. Vor dem Ausführen der Anforderung an den Dienst zählen wir die Anzahl der bereits geladenen Einträge (aktuelleEinträge Variable) und berechnen, wie viele Einträge der Dienst abrufen muss (entryToShow Variable). Dann führen wir die AJAX-Anfrage mit der jQuery aus Ajax () Methode und gleichzeitig zeigen wir dem Benutzer das Widget zum Laden der Seite. Wenn der Erfolgsrückruf ausgeführt wird, testen wir zunächst, ob die Anzahl der zurückgegebenen Einträge mit der bereits angezeigten Anzahl übereinstimmt. In diesem Fall wird die Meldung "Keine weiteren Einträge zum Laden" angezeigt. Andernfalls hängen wir sie an die Liste an und aktualisieren das Akkordeon-Widget ($ list.collapsibleset ('refresh')). Neben jedem Eintrag fügen wir auch einen Handler an die Schaltfläche an, die erstellt wird. Wenn die Verbindung getrennt ist, wird eine Meldung angezeigt, anstatt auf die Seite zuzugreifen.

Endlich, das updateIcons () Methode wird im nächsten und letzten Teil der Serie besprochen.

Der Code, der die besprochene Klasse implementiert, ist unten aufgeführt:

 var Application = initApplication: function () $ (document) .on ('pageinit', '# add-feed-page'), function () Application.initAddFeedPage ();) .on ('pageinit', ' # list-feeds-page ', function () Application.initListFeedPage ();) .on (' pageinit ',' # show-feed-page ', function () var url = this.getAttribute (' data- url '). replace (/(.*?) url = / g, "); Application.initShowFeedPage (url);) .on (' pageinit ',' # aurelio-page ') function () Application.initAurelioPage ();) .on ('backbutton', function () $ .mobile.changePage ('index.html');); Application.openLinksInApp ();, initAddFeedPage: function () $ ('# add-feed-form '). submit (Funktion (Ereignis) event.preventDefault (); var feedName = $ (' # feed-name '). val (). trim (); var feedUrl = $ (' # feed) -url '). val (). trim (); if (feedName === ") navigator.notification.alert (' Namensfeld ist erforderlich und darf nicht leer sein ') function () ,' Error '); false zurückgeben; if (feedUrl === ") navigator.notification.alert ('URL-Feld ist erforderlich und darf nicht leer sein') function ()  , 'Error'); falsch zurückgeben;  if (Feed.searchByName (feedName) === false && Feed.searchByUrl (feedUrl) === false) var feed = neuer Feed (feedName, feedUrl); feed.add (); navigator.notification.alert ('Feed wurde korrekt gespeichert', function () $ .mobile.changePage ('index.html');, 'Erfolg');  else navigator.notification.alert ('Feed wurde nicht gespeichert! Entweder wird der angegebene Name oder die angegebene URL verwendet', function () , 'Error');  falsch zurückgeben; ); , initListFeedPage: function () var $ feedsList = $ ('# feeds-list'); var items = Feed.getFeeds (); var htmlItems = "; $ feedsList.empty (); items = items.sort (Feed.compare); for (var i = 0; i < items.length; i++)  htmlItems += '
  • '+ items [i] .name +'
  • '; $ feedsList.append (htmlItems) .listview ('refresh'); , initShowFeedPage: function (url) var step = 10; var loadFeed = function () var currentEntries = $ ('# feed-entries'). find ('div [Datenrolle = zusammenklappbar]'). length; var entriesToShow = currentEntries + step; $ .ajax (url: 'https://ajax.googleapis.com/ajax/services/feed/load?v=1.0&num=' + entriesToShow + '& q =' + encodeURI (url), datentyp: 'json' , beforeSend: function () $ .mobile.loading ('show', text: 'Bitte warten Sie, während Daten abgerufen werden ...', textVisible: true);, success: function (data) var $ list = $ ( '# feed-entries'); if (data.responseData === null) navigator.notification.alert ('Feed kann nicht abgerufen werden. Ungültige URL', function () , 'Error'); return; var items = data.responseData.feed.entries; var $ post; if (aktuelleEntries === items.length) navigator.notification.alert ('Keine weiteren Einträge zum Laden', function () , 'Info') ; return; for (var i = aktuelle Einträge; i < items.length; i++) $post = $('
    '); $ post .append ($ ('

    ') .text (items [i] .title)) .append ($ ('

    ') .html (' '+ items [i] .title +' ')) // Titel hinzufügen .append ($ ('

    ') .html (items [i] .contentSnippet)) // Beschreibung hinzufügen .append ($ ('

    ') .text (' Author: '+ items [i] .author)) .append ($ (' ') .text (' Gehe zum Artikel ') .button () .click (Funktion (Ereignis) if ( Application.checkRequirements () === false) event.preventDefault (); navigator.notification.alert ('Die Verbindung ist deaktiviert, bitte einschalten.') Function () , 'Error'); false zurückgeben; $ (this) .removeClass ('ui-btn-active');)); $ list.append ($ post); $ list.collapsibleset ('refresh'); , error: function () navigator.notification.alert ('Feed kann nicht abgerufen werden. Versuchen Sie es später.') function () , 'Error'); , complete: function () $ .mobile.loading ('hide'); ); ; $ ('# show-more-entries'). click (function () loadFeed (); $ (this) .removeClass ('ui-btn-active');); $ ('# delete-feed'). click (function () Feed.searchByUrl (url) .delete (); navigator.notification.alert ('Feed gelöscht', function () $ .mobile.changePage ('list.) -feeds.html ');,' Erfolg ');); if (Application.checkRequirements () === true) loadFeed (); else navigator.notification.alert ('Um diese App verwenden zu können, müssen Sie Ihre Internetverbindung aktivieren', function () , 'Warning'); , initAurelioPage: function () $ ('a [target = _blank]'). click (function () $ (this) .closest ('li'). removeClass ('ui-btn-active'); ); , checkRequirements: function () if (navigator.connection.type === Connection.NONE) return false; return true; , updateIcons: function () var $ buttons = $ ('ein [Daten-Symbol], Schaltfläche [Daten-Symbol]'); var isMobileWidth = ($ (window) .width () <= 480); isMobileWidth ? $buttons.attr('data-iconpos', 'notext') : $buttons.removeAttr('data-iconpos'); , openLinksInApp: function () $(document).on('click', 'a[target=_blank]', function (event) event.preventDefault(); window.open($(this).attr('href'), '_blank'); ); ;


    Fazit

    In der dritten und letzten Installation dieser Serie erfahren Sie, wie Sie die Installationsprogramme mithilfe der CLI und Adobe PhoneGap Build erstellen und testen.