שלב 4: פתיחת קישורים חיצוניים באמצעות WebView

בשלב הזה תלמדו:

  • כיצד להציג תוכן אינטרנט חיצוני באפליקציה שלכם באופן מאובטח וארגז חול.

זמן משוער להשלמת השלב הזה: 10 דקות.
כדי לראות תצוגה מקדימה של מה שתשלימו בשלב הזה, דלגו לתחתית הדף הזה ↓.

מידע נוסף על תג WebView

אפליקציות מסוימות צריכות להציג תוכן אינטרנט חיצוני ישירות למשתמש אבל להשאיר אותו בתוך חוויית השימוש באפליקציה. לדוגמה, יכול להיות שאתר אגרגטור של חדשות ירצה להטמיע חדשות ממקורות חיצוניים אתרים עם כל העיצוב, התמונות וההתנהגות של האתר המקורי. לאפשרויות האלה ואחרות בשימוש, לאפליקציות Chrome יש תג HTML מותאם אישית שנקרא WebView.

אפליקציית Todo באמצעות WebView

הטמעה של תג WebView

מעדכנים את אפליקציית Todo כדי לחפש כתובות URL בטקסט של הפריט לביצוע משימות וליצור היפר-קישור. הקישור, כאשר כשלוחצים עליו, נפתח חלון חדש של אפליקציית Chrome (לא כרטיסייה בדפדפן) עם WebView שמציג את התוכן.

עדכון ההרשאות

ב-manifest.json, מבקשים את ההרשאה webview:

"permissions": [
  "storage",
  "alarms",
  "notifications",
  "webview"
],

יצירת דף של כלי הטמעה של WebView

יוצרים קובץ חדש ברמה הבסיסית (root) של תיקיית הפרויקט ונותנים לו את השם webview.html. הקובץ הזה הוא דף אינטרנט בסיסי עם תג <webview> אחד:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
</head>
<body>
  <webview style="width: 100%; height: 100%;"></webview>
</body>
</html>

ניתוח של כתובות URL בפריטי משימות לביצוע

בסוף controller.js, מוסיפים שיטה חדשה בשם _parseForURLs():

  Controller.prototype._getCurrentPage = function () {
    return document.location.hash.split('/')[1];
  };

  Controller.prototype._parseForURLs = function (text) {
    var re = /(https?:\/\/[^\s"<>,]+)/g;
    return text.replace(re, '<a href="$1" data-src="$1">$1</a>');
  };

  // Export to window
  window.app.Controller = Controller;
})(window);

בכל פעם שמחרוזת מתחילה ב-"http:// " או "https:// " נמצא, נוצר תג עוגן של HTML שמקיפים את כתובת ה-URL.

מוצאים את showAll() ב-controller.js. צריך לעדכן את showAll() כדי לנתח קישורים באמצעות השיטה _parseForURLs() נוספה בעבר:

/**
 * An event to fire on load. Will get all items and display them in the
 * todo-list
 */
Controller.prototype.showAll = function () {
  this.model.read(function (data) {
    this.$todoList.innerHTML = this.view.show(data);
    this.$todoList.innerHTML = this._parseForURLs(this.view.show(data));
  }.bind(this));
};

חוזרים על הפעולות האלה לגבי showActive() ו-showCompleted():

/**
 * Renders all active tasks
 */
Controller.prototype.showActive = function () {
  this.model.read({ completed: 0 }, function (data) {
    this.$todoList.innerHTML = this.view.show(data);
    this.$todoList.innerHTML = this._parseForURLs(this.view.show(data));
  }.bind(this));
};

/**
 * Renders all completed tasks
 */
Controller.prototype.showCompleted = function () {
  this.model.read({ completed: 1 }, function (data) {
    this.$todoList.innerHTML = this.view.show(data);
    this.$todoList.innerHTML = this._parseForURLs(this.view.show(data));
  }.bind(this));
};

לסיום, מוסיפים את _parseForURLs() אל editItem():

Controller.prototype.editItem = function (id, label) {
  ...
  var onSaveHandler = function () {
    ...
      // Instead of re-rendering the whole view just update
      // this piece of it
      label.innerHTML = value;
      label.innerHTML = this._parseForURLs(value);
    ...
  }.bind(this);
  ...
}

עדיין ב-editItem(), מתקנים את הקוד כך שישתמש ב-innerText של התווית במקום ב innerHTML של התווית:

Controller.prototype.editItem = function (id, label) {
  ...
  // Get the innerHTML of the label instead of requesting the data from the
  // Get the innerText of the label instead of requesting the data from the
  // ORM. If this were a real DB this would save a lot of time and would avoid
  // a spinner gif.
  input.value = label.innerHTML;
  input.value = label.innerText;
  ...
}

פתיחת חלון חדש עם WebView

מוסיפים method _doShowUrl() ל-controller.js. בשיטה הזו נפתח חלון חדש של אפליקציית Chrome דרך chrome.app.window.create() עם webview.html כמקור החלון:

  Controller.prototype._parseForURLs = function (text) {
    var re = /(https?:\/\/[^\s"<>,]+)/g;
    return text.replace(re, '<a href="$1" data-src="$1">$1</a>');
  };

  Controller.prototype._doShowUrl = function(e) {
    // only applies to elements with data-src attributes
    if (!e.target.hasAttribute('data-src')) {
      return;
    }
    e.preventDefault();
    var url = e.target.getAttribute('data-src');
    chrome.app.window.create(
     'webview.html',
     {hidden: true},   // only show window when webview is configured
     function(appWin) {
       appWin.contentWindow.addEventListener('DOMContentLoaded',
         function(e) {
           // when window is loaded, set webview source
           var webview = appWin.contentWindow.
                document.querySelector('webview');
           webview.src = url;
           // now we can show it:
           appWin.show();
         }
       );
     });
  };

  // Export to window
  window.app.Controller = Controller;
})(window);

בקריאה החוזרת (callback) של chrome.app.window.create(), חשוב לראות איך כתובת ה-URL של WebView מוגדרת באמצעות התג src .

לסיום, מוסיפים האזנה לאירוע קליק בתוך ה-constructor של Controller כדי לקרוא ל-doShowUrl() כאשר משתמש לוחץ על קישור:

function Controller(model, view) {
  ...
  this.router = new Router();
  this.router.init();

  this.$todoList.addEventListener('click', this._doShowUrl);

  window.addEventListener('load', function () {
    this._updateFilterState();
  }.bind(this));
  ...
}

הפעלה של אפליקציית Todo שסיימת

סיימת את שלב 4! אם תטענו מחדש את האפליקציה ותוסיפו פריט משימות לביצוע עם כתובת URL מלאה שמתחילה ב- http:// או https://, אתם אמורים לראות משהו כזה:

אפשר לקבל מידע נוסף

למידע מפורט יותר על כמה מממשקי ה-API שהוצגו בשלב הזה, אפשר לעיין במאמרים הבאים:

מוכנים להמשיך לשלב הבא? עבור אל שלב 5 - הוספת תמונות מהאינטרנט »