[譯]介紹一下漸進式 Web App(訊息推送) – Part 3

naice發表於2019-03-01

在第一篇:介紹一下漸進式 Web App(離線) – Part 1中我們介紹了一個典型的PWA應該是什麼樣子的,並且介紹了一下sercer worker和應用殼(app shell),在第二篇介紹一下漸進式 Web App(即時載入) – Part 2
文章中,我們快取了動態資料,並實現了從本地儲存的資料中即時載入資料到頁面中,也順便介紹了web的一些資料庫。

這篇文章也是這系列的完結篇,我們將實現:

  • 在Web應用程式中啟用推送通知
  • 使Web應用程式的變成是可以可安裝的

訊息推送

push API使Web應用程式能夠接收從伺服器推送來的訊息並通知使用者。這個功能需要service worker配合起來,在Web應用程式中典型的推送通知流程的過程是這樣子滴:

  • Web應用程式彈出一個彈出視窗,要求使用者訂閱通知。
  • 使用者訂閱接收推送通知。
  • service worker 負責管理、處理使用者的訂閱。
  • 當伺服器推送訊息時都會用到使用者訂閱的ID,每個使用者根據他們的訂閱ID都可以有一個自定義的功能。
  • 在service worker的push的監聽事件下,可以接收任何傳入的訊息。

讓我們開始吧。

我們先快速總結一下,訊息推送時怎麼在我們的web app中實現的

  1. 給使用者一個開關,單擊一個按鈕啟用或停用推送通知。
  2. 如果使用者啟用,請訂閱使用者通過service worker的管理接收推送通知。
  3. 構建一個API 去處理使用者刪除或者儲存訂閱ID。這個API也將負責向已啟用推送訊息的所有使用者傳送訊息。
  4. 建立一個GitHub Webhook去實現立即傳送通知,讓新的提交被推送到resources-i-like倉庫

程式碼行動起來

在專案中新建js/notification.js檔案,並且在index.html中引用。

<script src="./js/notification.js"></script>
複製程式碼

js/notification.js 程式碼如下

(function (window) {
  `use strict`;

  //Push notification button
  var fabPushElement = document.querySelector(`.fab__push`);
  var fabPushImgElement = document.querySelector(`.fab__image`);

  //To check `push notification` is supported or not
  function isPushSupported() {
    //To check `push notification` permission is denied by user
    if (Notification.permission === `denied`) {
      alert(`User has blocked push notification.`);
      return;
    }

    //Check `push notification` is supported or not
    if (!(`PushManager` in window)) {
      alert(`Sorry, Push notification isn`t supported in your browser.`);
      return;
    }

    //Get `push notification` subscription
    //If `serviceWorker` is registered and ready
    navigator.serviceWorker.ready
      .then(function (registration) {
        registration.pushManager.getSubscription()
        .then(function (subscription) {
          //If already access granted, enable push button status
          if (subscription) {
            changePushStatus(true);
          }
          else {
            changePushStatus(false);
          }
        })
        .catch(function (error) {
          console.error(`Error occurred while enabling push `, error);
        });
      });
  }

  // Ask User if he/she wants to subscribe to push notifications and then 
  // ..subscribe and send push notification
  function subscribePush() {
    navigator.serviceWorker.ready.then(function(registration) {
      if (!registration.pushManager) {
        alert(`Your browser doesn`t support push notification.`);
        return false;
      }

      //To subscribe `push notification` from push manager
      registration.pushManager.subscribe({
        userVisibleOnly: true //Always show notification when received
      })
      .then(function (subscription) {
        toast(`Subscribed successfully.`);
        console.info(`Push notification subscribed.`);
        console.log(subscription);
        //saveSubscriptionID(subscription);
        changePushStatus(true);
      })
      .catch(function (error) {
        changePushStatus(false);
        console.error(`Push notification subscription error: `, error);
      });
    })
  }

  // Unsubscribe the user from push notifications
  function unsubscribePush() {
    navigator.serviceWorker.ready
    .then(function(registration) {
      //Get `push subscription`
      registration.pushManager.getSubscription()
      .then(function (subscription) {
        //If no `push subscription`, then return
        if(!subscription) {
          alert(`Unable to unregister push notification.`);
          return;
        }

        //Unsubscribe `push notification`
        subscription.unsubscribe()
          .then(function () {
            toast(`Unsubscribed successfully.`);
            console.info(`Push notification unsubscribed.`);
            console.log(subscription);
            //deleteSubscriptionID(subscription);
            changePushStatus(false);
          })
          .catch(function (error) {
            console.error(error);
          });
      })
      .catch(function (error) {
        console.error(`Failed to unsubscribe push notification.`);
      });
    })
  }

  //To change status
  function changePushStatus(status) {
    fabPushElement.dataset.checked = status;
    fabPushElement.checked = status;
    if (status) {
      fabPushElement.classList.add(`active`);
      fabPushImgElement.src = `../images/push-on.png`;
    }
    else {
     fabPushElement.classList.remove(`active`);
     fabPushImgElement.src = `../images/push-off.png`;
    }
  }

  //Click event for subscribe push
  fabPushElement.addEventListener(`click`, function () {
    var isSubscribed = (fabPushElement.dataset.checked === `true`);
    if (isSubscribed) {
      unsubscribePush();
    }
    else {
      subscribePush();
    }
  });

  isPushSupported(); //Check for push notification support
})(window);
複製程式碼

上面的程式碼做了很多事情。放心啦,我將會解釋一波程式碼的功能滴。

//Push notification button
  var fabPushElement = document.querySelector(`.fab__push`);
  var fabPushImgElement = document.querySelector(`.fab__image`);
複製程式碼
[譯]介紹一下漸進式 Web App(訊息推送) – Part 3

上面的程式碼獲取推送通知啟用和停用按鈕的節點。

function isPushSupported() {
    //To check `push notification` permission is denied by user
    if (Notification.permission === `denied`) {
      alert(`User has blocked push notification.`);
      return;
    }

    //Check `push notification` is supported or not
    if (!(`PushManager` in window)) {
      alert(`Sorry, Push notification isn`t supported in your browser.`);
      return;
    }

    //Get `push notification` subscription
    //If `serviceWorker` is registered and ready
    navigator.serviceWorker.ready
      .then(function (registration) {
        registration.pushManager.getSubscription()
        .then(function (subscription) {
          //If already access granted, enable push button status
          if (subscription) {
            changePushStatus(true);
          }
          else {
            changePushStatus(false);
          }
        })
        .catch(function (error) {
          console.error(`Error occurred while enabling push `, error);
        });
      });
  }
複製程式碼

上面的程式碼是檢查瀏覽器以是否支援推送通知。現在,最重要的是 service worker 必須註冊並且在您嘗試訂閱使用者以接收推送通知之前,已經做好了準備(ready)。因此,上面的程式碼也檢查service worker是否ready並獲得使用者的訂閱。

 //To change status
  function changePushStatus(status) {
    fabPushElement.dataset.checked = status;
    fabPushElement.checked = status;
    if (status) {
      fabPushElement.classList.add(`active`);
      fabPushImgElement.src = `../images/push-on.png`;
    }
    else {
     fabPushElement.classList.remove(`active`);
     fabPushImgElement.src = `../images/push-off.png`;
    }
  }
複製程式碼
[譯]介紹一下漸進式 Web App(訊息推送) – Part 3
[譯]介紹一下漸進式 Web App(訊息推送) – Part 3

使用者訂閱按鈕的樣式改變

changePushStatus函式代表著只需更改按鈕的顏色來指示使用者是否已訂閱。

// Ask User if he/she wants to subscribe to push notifications and then 
  // ..subscribe and send push notification
  function subscribePush() {
    navigator.serviceWorker.ready.then(function(registration) {
      if (!registration.pushManager) {
        alert(`Your browser doesn`t support push notification.`);
        return false;
      }

      //To subscribe `push notification` from push manager
      registration.pushManager.subscribe({
        userVisibleOnly: true //Always show notification when received
      })
      .then(function (subscription) {
        toast(`Subscribed successfully.`);
        console.info(`Push notification subscribed.`);
        console.log(subscription);
        //saveSubscriptionID(subscription);
        changePushStatus(true);
      })
      .catch(function (error) {
        changePushStatus(false);
        console.error(`Push notification subscription error: `, error);
      });
    })
  }
複製程式碼

上面的程式碼負責彈出請求使用者是否允許或阻止瀏覽器中的推送訊息。如果使用者允許推送訊息,就是彈出一個toast的已經允許的提示,然後更改按鈕的顏色並儲存訂閱ID。如果推瀏覽器不支援,那麼它會通知使用者它不受支援。

注意:儲存訂閱ID的功能現在已被註釋掉。

[譯]介紹一下漸進式 Web App(訊息推送) – Part 3
[譯]介紹一下漸進式 Web App(訊息推送) – Part 3
// Unsubscribe the user from push notifications
  function unsubscribePush() {
    navigator.serviceWorker.ready
    .then(function(registration) {
      //Get `push subscription`
      registration.pushManager.getSubscription()
      .then(function (subscription) {
        //If no `push subscription`, then return
        if(!subscription) {
          alert(`Unable to unregister push notification.`);
          return;
        }

        //Unsubscribe `push notification`
        subscription.unsubscribe()
          .then(function () {
            toast(`Unsubscribed successfully.`);
            console.info(`Push notification unsubscribed.`);
            //deleteSubscriptionID(subscription);
            changePushStatus(false);
          })
          .catch(function (error) {
            console.error(error);
          });
      })
      .catch(function (error) {
        console.error(`Failed to unsubscribe push notification.`);
      });
    })
  }
複製程式碼

上面的是負責退訂推送訊息,彈出一個toast提示小心,然後更改按鈕的顏色並刪除訂閱ID。

注意:刪除訂閱ID的功能現在已被註釋掉了。

[譯]介紹一下漸進式 Web App(訊息推送) – Part 3

 //Click event for subscribe push
  fabPushElement.addEventListener(`click`, function () {
    var isSubscribed = (fabPushElement.dataset.checked === `true`);
    if (isSubscribed) {
      unsubscribePush();
    }
    else {
      subscribePush();
    }
  });
複製程式碼

上面程式碼是新增一個按鈕單擊事件實現訂閱和取消訂閱使用者的切換。

處理訂閱ID

我們已經能夠看到推送訂閱了。現在,我們需要能夠儲存每個使用者的訂閱ID,當使用者退訂的推送通知時我們還需要能夠刪除這些訂閱ID。

新增下面的程式碼到你的js/notification.js

function saveSubscriptionID(subscription) {
    var subscription_id = subscription.endpoint.split(`gcm/send/`)[1];

    console.log("Subscription ID", subscription_id);

    fetch(`http://localhost:3333/api/users`, {
      method: `post`,
      headers: {
        `Accept`: `application/json`,
        `Content-Type`: `application/json`
      },
      body: JSON.stringify({ user_id : subscription_id })
    });
}

function deleteSubscriptionID(subscription) {
    var subscription_id = subscription.endpoint.split(`gcm/send/`)[1];

    fetch(`http://localhost:3333/api/user/` + subscription_id, {
      method: `delete`,
      headers: {
        `Accept`: `application/json`,
        `Content-Type`: `application/json`
      }
    });
}
複製程式碼

在上面的程式碼中,我們從伺服器請求一個介面,來獲取訂閱ID和和刪除訂閱ID,saveSubscriptionID函式建立了一個新的使用者並且儲存了使用者的訂閱ID,deleteSubscriptionID刪除了使用者和使用者的訂閱ID

看起來怪怪的。為什麼要請求到伺服器?簡單,因為我們需要一個資料庫來儲存所有的訂閱ID,這樣子就可以向所有的使用者傳送訊息推送。

API Service

這個API Service 處理了儲存和刪除訂閱ID同時也處理了訊息推送的功能。這API的分解。它將有3個api路由:

  1. POST /api/users建立新使用者並儲存其訂閱ID
  2. DELETE /api/user/:user_id刪除和取消訂閱使用者
  3. POST /api/notify向所有訂閱使用者傳送通知

很高興,我有API Service的原始碼,道友可以點選連結檢視,執行時候確保你的nodemongodb是事先安裝過的。克隆xi下來並且在命令列中執行node server.js

[譯]介紹一下漸進式 Web App(訊息推送) – Part 3

確保你先建立.env檔案,如下圖所示

[譯]介紹一下漸進式 Web App(訊息推送) – Part 3

溫馨提醒:您可以通過這個良好的教程去了解如何設定API服務。在本教程我只是實現了node.js版本的API服務。

我們將使用Firebase Cloud Messaging 作為我們的訊息服務。所以,現在用Firebase去建立一個新的專案。新建專案完了之後就去Project settings > Cloud Messaging這裡

[譯]介紹一下漸進式 Web App(訊息推送) – Part 3

拿到你的 Server Key然後複製貼上到你的.env檔案在的FCM_API_KEY,通過我們的API Server我們需要將Server Key傳給Firebase,下面看看我們的看看我們的訊息推送控制器的程式碼:

....

notifyUsers: function(req, res){

    var sender = new gcm.Sender(secrets.fcm);

    // Prepare a message to be sent
    var message = new gcm.Message({
        notification: {
          title: "New commit on Github Repo: RIL",
          icon: "ic_launcher",
          body: "Click to see the latest commit`"
        }
    });

    User.find({}, function(err, users) {

      // user subscription ids to deliver message to
      var user_ids = _.map(users, `user_id`);

      console.log("User Ids", user_ids);

      // Actually send the message
      sender.send(message, { registrationTokens: user_ids }, function (err, response) {
        if (err) {
            console.error(err);
        } else {
          return res.json(response);
        } 
      });
    });

  },

  .....
複製程式碼

現在返回我們的js/notification.js並且去掉我們之前說的saveSubscriptionID函式和deleteSubscriptionID的註釋,然後你的notification.js應該是長這樣子滴:

(function (window) {
  `use strict`;

  //Push notification button
  var fabPushElement = document.querySelector(`.fab__push`);
  var fabPushImgElement = document.querySelector(`.fab__image`);

  //To check `push notification` is supported or not
  function isPushSupported() {
    //To check `push notification` permission is denied by user
    if (Notification.permission === `denied`) {
      alert(`User has blocked push notification.`);
      return;
    }

    //Check `push notification` is supported or not
    if (!(`PushManager` in window)) {
      alert(`Sorry, Push notification isn`t supported in your browser.`);
      return;
    }

    //Get `push notification` subscription
    //If `serviceWorker` is registered and ready
    navigator.serviceWorker.ready
      .then(function (registration) {
        registration.pushManager.getSubscription()
        .then(function (subscription) {
          //If already access granted, enable push button status
          if (subscription) {
            changePushStatus(true);
          }
          else {
            changePushStatus(false);
          }
        })
        .catch(function (error) {
          console.error(`Error occurred while enabling push `, error);
        });
      });
  }

  // Ask User if he/she wants to subscribe to push notifications and then 
  // ..subscribe and send push notification
  function subscribePush() {
    navigator.serviceWorker.ready.then(function(registration) {
      if (!registration.pushManager) {
        alert(`Your browser doesn`t support push notification.`);
        return false;
      }

      //To subscribe `push notification` from push manager
      registration.pushManager.subscribe({
        userVisibleOnly: true //Always show notification when received
      })
      .then(function (subscription) {
        toast(`Subscribed successfully.`);
        console.info(`Push notification subscribed.`);
        console.log(subscription);
        saveSubscriptionID(subscription);
        changePushStatus(true);
      })
      .catch(function (error) {
        changePushStatus(false);
        console.error(`Push notification subscription error: `, error);
      });
    })
  }

  // Unsubscribe the user from push notifications
  function unsubscribePush() {
    navigator.serviceWorker.ready
    .then(function(registration) {
      //Get `push subscription`
      registration.pushManager.getSubscription()
      .then(function (subscription) {
        //If no `push subscription`, then return
        if(!subscription) {
          alert(`Unable to unregister push notification.`);
          return;
        }

        //Unsubscribe `push notification`
        subscription.unsubscribe()
          .then(function () {
            toast(`Unsubscribed successfully.`);
            console.info(`Push notification unsubscribed.`);
            console.log(subscription);
            deleteSubscriptionID(subscription);
            changePushStatus(false);
          })
          .catch(function (error) {
            console.error(error);
          });
      })
      .catch(function (error) {
        console.error(`Failed to unsubscribe push notification.`);
      });
    })
  }

  //To change status
  function changePushStatus(status) {
    fabPushElement.dataset.checked = status;
    fabPushElement.checked = status;
    if (status) {
      fabPushElement.classList.add(`active`);
      fabPushImgElement.src = `../images/push-on.png`;
    }
    else {
     fabPushElement.classList.remove(`active`);
     fabPushImgElement.src = `../images/push-off.png`;
    }
  }

  //Click event for subscribe push
  fabPushElement.addEventListener(`click`, function () {
    var isSubscribed = (fabPushElement.dataset.checked === `true`);
    if (isSubscribed) {
      unsubscribePush();
    }
    else {
      subscribePush();
    }
  });

  function saveSubscriptionID(subscription) {
    var subscription_id = subscription.endpoint.split(`gcm/send/`)[1];

    console.log("Subscription ID", subscription_id);

    fetch(`http://localhost:3333/api/users`, {
      method: `post`,
      headers: {
        `Accept`: `application/json`,
        `Content-Type`: `application/json`
      },
      body: JSON.stringify({ user_id : subscription_id })
    });
  }

  function deleteSubscriptionID(subscription) {
    var subscription_id = subscription.endpoint.split(`gcm/send/`)[1];

    fetch(`http://localhost:3333/api/user/` + subscription_id, {
      method: `delete`,
      headers: {
        `Accept`: `application/json`,
        `Content-Type`: `application/json`
      }
    });
  }

  isPushSupported(); //Check for push notification support
})(window);
複製程式碼

讓我們嘗試啟用訊息推送,看看是否建立了新的使用者,並儲存在我們的API服務資料庫中。重新重新整理網頁並按下啟用按鈕,然後看到控制檯居然有錯誤。

[譯]介紹一下漸進式 Web App(訊息推送) – Part 3

別煩惱!著原因是我們沒有在我們的程式中創一個manifest.json的檔案。
現在有趣的事情是,新增上了manifest.json的檔案將不會報錯並且在我們的程式中新增了一個新的功能。有了這個manifest.json的檔案,我們可以將我們的應用程式安裝到我們的螢幕上。Viola!!!

現在我們去建立一個manifest.json的檔案吧,程式碼如下


{
  "name": "PWA - Commits",
  "short_name": "PWA",
  "description": "Progressive Web Apps for Resources I like",
  "start_url": "./index.html?utm=homescreen",
  "display": "standalone",
  "orientation": "portrait",
  "background_color": "#f5f5f5",
  "theme_color": "#f5f5f5",
  "icons": [
    {
      "src": "./images/192x192.png",
      "type": "image/png",
      "sizes": "192x192"
    },
    {
      "src": "./images/168x168.png",
      "type": "image/png",
      "sizes": "168x168"
    },
    {
      "src": "./images/144x144.png",
      "type": "image/png",
      "sizes": "144x144"
    },
    {
      "src": "./images/96x96.png",
      "type": "image/png",
      "sizes": "96x96"
    },
    {
      "src": "./images/72x72.png",
      "type": "image/png",
      "sizes": "72x72"
    },
    {
      "src": "./images/48x48.png",
      "type": "image/png",
      "sizes": "48x48"
    }
  ],
  "author": {
    "name": "Prosper Otemuyiwa",
    "website": "https://twitter.com/unicodeveloper",
    "github": "https://github.com/unicodeveloper",
    "source-repo": "https://github.com/unicodeveloper/pwa-commits"
  },
  "gcm_sender_id": "571712848651"
}
複製程式碼

現在快速的掃盲一下manifest.json上的key的含義吧。

  • name:表示應用程式的名稱,因為它通常顯示在螢幕上給使用者看滴。
  • short_name:表示Web應用程式名稱的縮寫。
  • description:表示Web應用程式的一般描述。
  • start_url:是使用者啟動Web應用程式時載入的URL。
  • display:定義Web應用程式的預設顯示模式。不同的模式有fullscreen, standalone, minimal-ui
  • orientation:
  • background_color:表示Web應用程式的背景顏色。
  • theme_color:表示應用程式的預設主題顏色。它將Android上的狀態列著色。
  • icons:主螢幕的icon圖示
  • author:作者的一些資訊
  • gcm_sender_id:用於識別應用的Firebasesender_id,在下面取得。如下圖
[譯]介紹一下漸進式 Web App(訊息推送) – Part 3

在你的index.htmllatest.html引用這個manifest.json檔案。


 <link rel="manifest" href="./manifest.json">
複製程式碼

現在,清楚快取,重新整理應用,然後點選訊息推動按鈕

[譯]介紹一下漸進式 Web App(訊息推送) – Part 3

然後看到 訂閱ID在控制檯中列印了出來,檢視下出資料庫,

Yaaay!!,中於起作用了呢

[譯]介紹一下漸進式 Web App(訊息推送) – Part 3

在資料庫中你可以看到使用者的訂閱ID了,這意味著,我們的請求是成功滴

小提示:RoboMongo是一個管理mongodb資料庫的圖形介面。

您可以嘗試取消訂閱,檢視它如何從API服務資料庫中刪除使用者。

傳送和接收推送訊息

在我們的service API中,我們做一個POST請求到/api/notify的路由,然後後臺接收到前端的請求繼續推送到Firebase Cloud Messaging的服務中。現在,這還是不夠滴,所以,我們還需要一種在瀏覽器中監聽和接受此通知的方法。

然後到Service Worker閃亮登場了,用它來監聽一個push的事件,在sw.js中,程式碼如下:



self.addEventListener(`push`, function(event) {

  console.info(`Event: Push`);

  var title = `New commit on Github Repo: RIL`;

  var body = {
    `body`: `Click to see the latest commit`,
    `tag`: `pwa`,
    `icon`: `./images/48x48.png`
  };

  event.waitUntil(
    self.registration.showNotification(title, body)
  );
});

複製程式碼

這段程式碼新增到sw.js。清快取,重新載入你的應用,現在我們利用postman去發起http://localhost:3333/api/notify請求

[譯]介紹一下漸進式 Web App(訊息推送) – Part 3

當發出通知時,我們的瀏覽器會歡迎這樣的通知:

[譯]介紹一下漸進式 Web App(訊息推送) – Part 3

接到通知後,當使用者單擊這個通知時,我們可以決定該怎麼做。然後新增下面這個程式碼到sw.js

self.addEventListener(`notificationclick`, function(event) {

  var url = `./latest.html`;

  event.notification.close(); //Close the notification

  // Open the app and navigate to latest.html after clicking the notification
  event.waitUntil(
    clients.openWindow(url)
  );

});
複製程式碼

這裡,上面的程式碼監聽使用者單擊通知時被觸發的事件。event.notification.close()是單擊後關閉通知。然後,將開啟一個瀏覽器新視窗或選項卡重新指向localhost:8080/latest.html地址。

提示:event.waitUntil()在我們的新視窗開啟之前,它就被呼叫了以確保瀏覽器不會終止我們的server worker

自動推送訊息

之前我們是通過Postman手動發起一個請求去推送訊息的,實際上,我們是想,用於一旦有了提交到https://github.com/unicodeveloper/resources-i-like/,我們就自動接收收到一個訊息通知。那麼,我們如何使這個過程自動化呢?

有聽說過Webhooks麼???

有!!!

那麼好~~我們就用GitHub Webhooks

提示: 使用您自己的倉庫地址,因為看到了這裡,你就要自己提交commit了

到你選擇的倉庫去,在這裡我的是https://github.com/unicodeveloper/resources-i-like/,到 Settings > Webhooks中:

[譯]介紹一下漸進式 Web App(訊息推送) – Part 3
[譯]介紹一下漸進式 Web App(訊息推送) – Part 3

點選add webhook新增一個hook,當使用者提交的時候就觸發了pushs是事件,這個hook講通知我們的notify API ,利用這個webhook當使用者提交commit時候,發出一個post請求到我們的/api/notify,然後順利成章的傳送一個瀏覽器的訊息推送啦。 開森~~~~

[譯]介紹一下漸進式 Web App(訊息推送) – Part 3

看上面那個圖,慢著,等一下,是怎麼得到https://ea71f5aa.ngrok.io/api/notifyz這個地址的??實際上是在本地開發需要用ngrok工具,把內網轉發出去。明白了吧

設定Ngrok

非常簡單,我們不能使用localhost,GitHub上需要一個存在在網路上URL,我利用ngrok可以將本地伺服器暴露到Internet上。

安裝ngrok之後,在命令列中,敲上這樣子的程式碼

./ngrok http 3333
複製程式碼

得到

[譯]介紹一下漸進式 Web App(訊息推送) – Part 3

提示:ngrok輸出HTTP和HTTPS地址,它們都對映到本地服務。

現在,一旦你新增webhook,GitHub立即提交測試post請求來決定是否設定正確。

[譯]介紹一下漸進式 Web App(訊息推送) – Part 3

測試一個commit吧

我們把一切都做好了,現在我們去提交一個commit,一旦你這麼做了,一個訊息推送就傳送到我們的瀏覽器中了。 如下圖

[譯]介紹一下漸進式 Web App(訊息推送) – Part 3

Host PWA

一個PWA的要求服務是通過HTTPS的。用Firebase hosting部署我們的應用程式伺服器並且支援HTTPS協議是一個非常好的選擇。

我們app線上的地址:ril-pwa.firebaseapp.com/
伺服器api線上地址:rilapi.herokuapp.com/api

新增應用到主螢幕

開啟你的裝置上的瀏覽器,尤其是Chrome,並像這樣新增它:

[譯]介紹一下漸進式 Web App(訊息推送) – Part 3
[譯]介紹一下漸進式 Web App(訊息推送) – Part 3
[譯]介紹一下漸進式 Web App(訊息推送) – Part 3

看到桌面上已經有了 應用圖示了。然後本教程也是總結鳥。

~~~~~ 完結,散花散花散花散花 ~~~~


附:

點選連結檢視

原文地址

第一篇: 介紹一下漸進式 Web App(離線) – Part 1

第二篇: 介紹一下漸進式 Web App(即時載入)- Part 2

專案PWA程式碼

專案API code程式碼

個人部落格地址


如果有那個地方翻譯出錯或者失誤,請各位大神不吝賜教,小弟感激不盡

相關文章