指南

如何為應用程式加入通知:應用程式內、電子郵件與推播

要為網頁應用程式加入通知,請先從應用程式內通知開始:在資料庫中建立通知資料表,並加上顯示未讀項目的鈴鐺圖示。若要在使用者離開時仍能得知重要事項,可以用電子郵件服務供應商加入電子郵件;只有在即時提醒真的重要時,才加入網頁推播,因為它需要 Service Worker、使用者授權,而在 iPhone 上還需要先把應用程式存到主畫面。無論使用哪些管道,都應該在伺服器上的同一個地方建立所有通知,並讓使用者選擇要接收哪些內容。

本指南會比較各種管道、展示一個簡單的架構,並提供可交給 AI 應用程式建置工具使用的提示詞。

主要管道比較

管道何時會觸及使用者設定投入持續成本最適合
應用程式內(鈴鐺、即時提示)使用者正在使用你的應用程式時低除了資料庫之外沒有其他費用活動、提及、狀態變更
電子郵件使用者任何時候查看信箱時中等:供應商、網域設定依供應商的每封郵件計費收據、摘要、重要事項
網頁推播瀏覽器或已安裝的網頁應用程式,即使已關閉中等到高通常免費發送對時間敏感的提醒
簡訊幾乎一定會看到中等;需遵守同意規則每則訊息收費預約提醒、緊急通知
聊天工具(Slack、Teams)使用者在工作時低到中等通常免費內部工具與團隊警示

大多數應用程式需要的是應用程式內加電子郵件。只有在時機真的很重要時,例如預約提醒或訂單已準備好,才值得加入推播和簡訊。

通知系統如何運作

保持簡單並集中管理:

  1. 事情發生了。 有人留言、付款失敗、預約就在明天。
  2. 你的伺服器呼叫一個函式,例如 notify(user, type, data)。
  3. 該函式檢查使用者的偏好設定,並把一筆資料寫入 notifications 資料表(供鈴鐺使用)。
  4. 接著發送到使用者為該類型開啟的其他管道:電子郵件透過你的供應商發送,推播則透過 Push API 發送。
  5. 前端顯示未讀通知,並在使用者打開時標記為已讀。

只設定一個入口,之後要新增管道、修改文字或遵守偏好設定,都不必在程式碼中四處尋找。

要儲存什麼

通知資料表通常需要:使用者 ID、類型(例如 comment_reply)、簡短的標題和內容、指向相關頁面的連結、建立時間,以及已讀時間。另外還需要一個偏好設定資料表,記錄每位使用者對每種類型想使用哪些管道。

顯示新通知

  • 載入頁面時取得,並每 30 到 60 秒輪詢一次。簡單而可靠。
  • 用 WebSocket 或 Server-Sent Events 即時更新,感覺更即時,但會增加運作元件。除非即時更新真的很重要,否則建議先用輪詢。

電子郵件通知

電子郵件需要寄送服務供應商和已驗證的網域;細節請見如何從應用程式寄送電子郵件。針對通知,請注意:

  • 從伺服器寄出,絕不要在瀏覽器中放入供應商金鑰。
  • 合併頻繁發生的事件。「3 則新留言」合併成一封信,勝過寄三封信。
  • 為低優先的活動提供每日或每週摘要。
  • **在非必要的電子郵件中加入取消訂閱或偏好設定連結。**各國對行銷郵件的規定不同,請確認適用於你的規定。

網頁推播通知

網頁推播讓你的網站發送看起來像應用程式通知的提醒。根據 MDN 的 Push API 文件,運作方式如下:

  1. 你的網站註冊一個 Service Worker,也就是瀏覽器可以在背景執行的腳本。
  2. 使用者同意後,Service Worker 透過 PushManager.subscribe() 訂閱。瀏覽器會回傳包含端點與加密金鑰的 訂閱資訊。
  3. 你的伺服器儲存該訂閱資訊;當事情發生時,會通常以 VAPID 金鑰(用來識別你伺服器的金鑰對)簽署,然後把訊息送到該端點。
  4. 瀏覽器會啟動你的 Service Worker,即使你的頁面沒有開啟,也會顯示通知。

MDN 也指出端點應保密,因為只要知道端點,就足以對該使用者發送訊息。

iPhone 與 iPad

WebKit 在 iOS 和 iPadOS 16.4 中為網頁應用程式加入了 Web Push,其公告中的兩項條件是:網站必須加到主畫面,而且權限必須在使用者的操作之後請求,例如點擊「訂閱」按鈕。因此在 iPhone 上,推播只會送達已安裝你網頁應用程式的使用者。什麼是安裝網頁應用程式,請參閱原生應用程式與漸進式網頁應用程式。

妥善請求權限

不要在使用者第一次造訪時就請求。先說明好處(「上課前一小時提醒你」),然後在使用者點擊按鈕時才顯示瀏覽器的權限視窗。如果使用者拒絕,瀏覽器可能不允許你再次詢問,因此過早請求可能會永久失去這位使用者。

排程通知需要觸發機制

「開始前 24 小時提醒」或「每週一的週摘要」需要有東西在排程上執行。這屬於背景工作的問題,請參閱如何執行背景工作。常見的做法是:外部排程器每隔幾分鐘呼叫一個受保護的端點,由該端點發送所有到期的通知。

交給 AI 建置工具的提示詞

先從應用程式內通知開始:

加入應用程式內通知。建立 notifications 資料表(user、type、title、body、link、created_at、read_at)。新增一個伺服器函式 notify(userId, type, data),讓每個功能都呼叫它。在標頭顯示帶有未讀數量的鈴鐺圖示,下拉選單列出最新 20 則,並提供「全部標為已讀」按鈕。每 60 秒輪詢一次新通知。

接著是偏好設定和電子郵件:

加入通知設定:針對每種類型(留言回覆、提及、帳單),讓使用者選擇應用程式內、電子郵件、兩者皆要或都不要。notify() 必須遵守這些設定。透過 [PROVIDER] 寄送電子郵件,並僅在伺服器上使用機密 [ENV_NAME]。把留言電子郵件合併,讓同一位使用者每 15 分鐘最多只收到一封。

如果需要,再加入推播:

加入選用的網頁推播。註冊 Service Worker,產生 VAPID 金鑰,並把私鑰儲存為機密。在設定中加入「啟用通知」按鈕,只有在點擊時才請求權限。依每位使用者和每台裝置儲存訂閱資訊,當使用者同意時由 notify() 發送推播,並刪除推播服務回報已過期的訂閱。

常見錯誤

  • **通知散落在程式各處。**每個功能各自以不同方式寄信,偏好設定也被忽略。請使用一個 notify() 函式。
  • **頁面載入時就請求推播權限。**大多數人會拒絕,而你可能不會再有機會。
  • **沒有偏好設定。**無法關閉吵人通知的使用者,會把所有通知都關掉,或直接離開。
  • **從瀏覽器發送。**電子郵件和推播的金鑰應該放在伺服器上。
  • **沒有清理失效的推播訂閱。**過期的訂閱會不斷累積,浪費發送資源。
  • **通知內容包含敏感細節。**鎖定畫面會顯示這些內容。「你有一則新訊息」比訊息本身更安全。
  • **沒有發送紀錄。**當使用者說「我沒收到電子郵件」,附有供應商訊息 ID 的紀錄能幫你找出原因。

檢查清單

  • 只使用一個伺服器端的 notify() 函式
  • 通知資料表包含已讀狀態,且鈴鐺顯示未讀數量
  • 依類型的管道偏好設定,並由 notify() 遵守
  • 電子郵件從伺服器寄出,使用已驗證的網域;頻繁發生的事件已摘要或合併
  • 推播權限只在使用者操作之後、且附有說明時才請求
  • 已在桌面與加到主畫面的 iPhone 上測試推播
  • 已移除失效的推播訂閱
  • 推播或電子郵件的預覽中沒有敏感內容
  • 排程提醒有可靠的觸發機制

Mythex 中的通知

Mythex 不為你建置的應用程式提供內建的電子郵件或推播服務,因此你需要自備電子郵件供應商,並產生自己的推播金鑰,儲存為專案機密。應用程式內通知部分只需要專案的資料庫,你請求時 Mythex 會加入。請用上述類似的提示詞建置,在預覽中測試鈴鐺和電子郵件,並在已發布的網址上測試推播,因為 Service Worker 和推播都需要真正的 HTTPS 位址。文件中的從應用程式寄送電子郵件食譜提供了起始提示詞。Mythex 並未說明排程工作的做法,因此請依照如何執行背景工作的說明,用外部觸發機制安排定時提醒。

常見問題

對網頁應用程式來說,最容易加入的通知是哪一種?

應用程式內通知:在資料庫中建立通知資料表,加上一個顯示未讀通知的鈴鐺圖示。這不需要任何第三方服務。電子郵件是下一步,需要電子郵件服務供應商。

網頁應用程式可以把推播通知傳到 iPhone 嗎?

可以,但有限制。WebKit 在 iOS 和 iPadOS 16.4 中為加到主畫面的網頁應用程式加入了 Web Push,因此使用者必須先把你的網頁應用程式加到主畫面,而且權限必須在點擊之後才請求,例如點擊「訂閱」按鈕。

網站關閉時,推播通知還能送達嗎?

可以。Push API 會把訊息送到你網站的 Service Worker,訊息抵達時瀏覽器會啟動它,因此頁面不需要保持開啟。使用者必須事先授予權限。

如何避免通知讓使用者感到煩躁?

只通知使用者真正在意的事,把連續發生的事件合併成一則訊息,讓使用者在設定中依類型選擇通知管道,並且只在使用者看過推播的好處之後,才請求推播權限。

Mythex · Pricing · 用 AI 打造任何東西 · 網站與應用程式範本 · Mythex 比較 · AI 應用程式開發詞彙表 · 免費的 AI 應用程式開發工具 · English

English አማርኛ العربية Български বাংলা Bosanski Català Čeština Dansk Deutsch Ελληνικά Español Español (España) Eesti فارسی Suomi Français Français (Canada) ગુજરાતી हिन्दी Hrvatski Magyar Հայերեն Bahasa Indonesia Íslenska Italiano 日本語 ქართული Қазақ тілі ಕನ್ನಡ 한국어 Lietuvių Latviešu Македонски മലയാളം Монгол मराठी Bahasa Melayu မြန်မာ Norsk bokmål Nederlands ਪੰਜਾਬੀ Polski Português (Brasil) Português (Portugal) Română Русский Slovenčina Slovenščina Soomaali Shqip Srpski Svenska Kiswahili தமிழ் తెలుగు ไทย Tagalog Türkçe Українська اردو Tiếng Việt 简体中文 繁體中文(香港)