如何建立應用程式徽章

徽章用於向使用者傳達非緊急資訊。舉例來說,這些圖示可用來表示應用程式的狀態,或未讀項目數量。建立應用程式徽章的傳統方式是在 Favicon 中加入數字。在現代瀏覽器中,應用程式安裝完成後,系統會內建方法,在作業系統的工作列中為應用程式圖示加上徽章。

現代做法

使用 navigator.setAppBadge() 方法

navigator.setAppBadge() 方法會在與安裝版應用程式相關聯的圖示上設定徽章。這個方法會採用選用的單一引數,也就是將做為徽章值的整數。將數字設為 0 可清除應用程式徽章。如果未提供引數,系統會顯示一般徽章,通常是彩色圓點。

應用程式圖示:實際圖示,徽章值為數字 3。

Browser Support

  • Chrome: 81.
  • Edge: 81.
  • Firefox: not supported.
  • Safari: 17.

Source

傳統做法

在網站小圖示中新增數字

如果尚未安裝應用程式,可以在 Favicon 中新增號碼。方法有很多種,例如將動態 Favicon 繪製到畫布上,並加入徽章資訊,然後以 Blob 網址的形式顯示,或是製作含有徽章資訊的 SVG 圖片,並以資料網址的形式顯示。

顯示實際圖示的網頁圖示,徽章值為 5。

漸進增強

下方程式碼片段使用自訂元素 <favicon-badge></favicon-badge>,開發人員可透過 src 屬性指定 Favicon,並將整數傳遞至 badge 屬性,以宣告方式在 Favicon 上設定徽章。使用者安裝應用程式後,徽章會「升級」為原生作業系統徽章。

import 'https://unpkg.com/favicon-badge@2.0.0/dist/FavIconBadge.js';

// DOM references.
const favicon = document.querySelector('favicon-badge');
const installButton = document.querySelector('button');

// Feature detection.
const supportsAppBadge = 'setAppBadge' in navigator;

let setAppBadge;

// For the demo simply set the badge between [0, 9].
let i = 0;
const getAppBadgeValue = () => {
  if (i > 9) {
    i = 0;
  }
  return i++;
};

// Set the badge on the favicon.
const setAppBadgeFavicon = (value) => {
  favicon.badge = value;
};

// Set the native operating system badge.
const setAppBadgeNative = (value) => {
  navigator.setAppBadge(value);
}

// If the app is installed and the Badging API is supported,
// set the badge on the native operating system. Else, fall
// back to the favicon.
if (
  matchMedia('(display-mode: standalone)').matches &&
  supportsAppBadge
) {
  setAppBadge = setAppBadgeNative;
} else {
  setAppBadge = setAppBadgeFavicon;
}

// Set a new badge every second.
setInterval(() => {
  setAppBadge(getAppBadgeValue());
}, 1000);

// If installation is supported…
if ('BeforeInstallPromptEvent' in window) {
  let installEvent = null;
  const onInstall = () => {
    // After installation, "upgrade" to the native operating system badge.
    installButton.disabled = true;
    installEvent = null;
    if (supportsAppBadge) {
      favicon.badge = false;
      setAppBadge = setAppBadgeNative;
    }
  };

  // …listen for the `beforeinstallprompt` event.
  window.addEventListener('beforeinstallprompt', (event) => {
    event.preventDefault();
    installEvent = event;
    installButton.disabled = false;
  });

  // Deal with installation.
  installButton.addEventListener('click', async () => {
    if (!installEvent) {
      return;
    }
    installEvent.prompt();
    const result = await installEvent.userChoice;
    if (result.outcome === 'accepted') {
      onInstall();
    }
  });

  // Listen for the `appinstalled` in case the user installs the app manually.
  window.addEventListener('appinstalled', (event) => {
    onInstall();
  });
}

延伸閱讀

示範

HTML

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="manifest" href="manifest.json" />
    <title>How to create an app badge</title>
    <link rel="stylesheet" href="style.css" />
    <!-- TODO: Devsite - Removed inline handlers -->
    <!-- <script>
      if ('serviceWorker' in navigator) {
        window.addEventListener('load', async () => {
          const registration = await navigator.serviceWorker.register(
            'sw.js',
          );
          console.log(
            'Service worker registered for scope',
            registration.scope,
          );
        });
      }
    </script>
    <script src="script.js" type="module"></script> -->
  </head>
  <body>
    <h1>How to create an app badge</h1>
    <ol>
      <li>
        Watch the favicon. You should see a counter that updates each second
        integrated into the favicon.
        <img
          src="../favicon.png"
          style="width: 250px; height: auto"
          width="528"
          height="74"
          alt="Favicon with counter."
        />
      </li>
      <li>
        Install the app by clicking the button below. After the installation,
        the button is disabled.
        <p>
          <button disabled type="button">Install</button>
        </p>
      </li>
      <li>
        Watch the app icon in your operating system's task bar. You should see a
        counter that updates each second as an app badge.
        <img
          src="../app-badge.png"
          style="width: 80px; height: auto"
          width="282"
          height="388"
          alt="App badge with counter."
        />
      </li>
    </ol>
    <favicon-badge src="../favicon.svg" textColor="#fff" badge="" />
  </body>
</html>

CSS


        html {
  box-sizing: border-box;
  font-family: system-ui, sans-serif;
  color-scheme: dark light;
}

*, *:before, *:after {
  box-sizing: inherit;
}

body {
  margin: 1rem;
}

img {
  height: auto;
  max-width: 100%;
  display: block;
}
        

JS


        import 'https://unpkg.com/favicon-badge@2.0.0/dist/FavIconBadge.js';

// The `` custom element.
const favicon = document.querySelector('favicon-badge');
// The install button.
const installButton = document.querySelector('button');

// Feature detection.
const supportsAppBadge = 'setAppBadge' in navigator;

// This function will either set the favicon or the native
// app badge. The implementation is dynamically changed at runtime.
let setAppBadge;

// Variable for the counter.
let i = 0;

// Returns a value between 0 and 9.
const getAppBadgeValue = () => {
  if (i > 9) {
    i = 0;
  }
  return i++;
};

// Function to set a favicon badge.
const setAppBadgeFavicon = (value) => {
  favicon.badge = value;
};

// Function to set a native app badge.
const setAppBadgeNative = (value) => {
  navigator.setAppBadge(value);
}

// If the app is installed and native app badges are supported,
// use the native app badge.
if (
  matchMedia('(display-mode: standalone)').matches &&
  supportsAppBadge
) {
  setAppBadge = setAppBadgeNative;
// In all other cases (i.e., if the app is not installed or native
//  app badges are not supported), use the favicon badge.
} else {
  setAppBadge = setAppBadgeFavicon;
}

// Update the badge every second.
setInterval(() => {
  setAppBadge(getAppBadgeValue());
}, 1000);

// Only relevant for browsers that support installation.
if ('BeforeInstallPromptEvent' in window) {
  // Variable to stash the `BeforeInstallPromptEvent`.
  let installEvent = null;

  // Function that will be run when the app is installed.
  const onInstall = () => {
    // Disable the install button.
    installButton.disabled = true;
    // No longer needed.
    installEvent = null;

    if (supportsAppBadge) {
      // Remove the favicon badge.
      favicon.badge = false;
      // Switch the implementation so it uses the native
      // app badge.
      setAppBadge = setAppBadgeNative;
    }
  };

  window.addEventListener('beforeinstallprompt', (event) => {
    // Do not show the install prompt quite yet.
    event.preventDefault();
    // Stash the `BeforeInstallPromptEvent` for later.
    installEvent = event;
    // Enable the install button.
    installButton.disabled = false;
  });

  installButton.addEventListener('click', async () => {
    // If there is no stashed `BeforeInstallPromptEvent`, return.
    if (!installEvent) {
      return;
    }
    // Use the stashed `BeforeInstallPromptEvent` to prompt the user.
    installEvent.prompt();
    const result = await installEvent.userChoice;
    // If the user installs the app, run `onInstall()`.
    if (result.outcome === 'accepted') {
      onInstall();
    }
  });

  // The user can decide to ignore the install button
  // and just use the browser prompt directly. In this case
  // likewise run `onInstall()`.
  window.addEventListener('appinstalled', (event) => {
    onInstall();
  });
}