MishiPay';PWA 提升了交易 10 倍,並省下 2.5 年的佇列

瞭解改用 PWA 如何協助 MishiPay 拓展業務。

有了 MishiPay,購物者就能使用智慧型手機掃描商品並付款,不必浪費時間在結帳櫃檯排隊。有了 MishiPay 的掃描即付技術,購物者就能使用自己的手機掃描商品上的條碼並付款,然後離開商店。研究顯示,全球零售業每年因店內排隊而損失 $2, 000 億美元

我們的技術仰賴裝置硬體功能,例如 GPS 感應器和攝影機,讓使用者可以找到啟用 MishiPay 的商店、掃描實體商店內的商品條碼,然後使用所選的數位付款方式付款。我們最初推出的「掃描即付」技術是專為 iOS 和 Android 平台設計的應用程式,早期採用者非常喜歡這項技術。請繼續閱讀,瞭解改用 PWA 後,交易次數如何增加 10 倍,並節省 2.5 年的排隊時間!

    10×

    交易量增加

    2.5 年

    已儲存佇列

挑戰

使用者在排隊等候或結帳時,會發現這項技術非常實用,因為他們可以跳過排隊,享受順暢的店內體驗。但下載 Android 或 iOS 應用程式的麻煩,導致使用者即使覺得我們的技術有價值,也不會選擇使用。這對 MishiPay 來說是日益嚴峻的挑戰,我們需要降低門檻,提高使用者採用率。

解決方案

我們致力於建構及推出 PWA,協助使用者免除安裝麻煩,並鼓勵新使用者在實體商店內試用我們的技術、跳過排隊,享受流暢的購物體驗。自推出以來,與平台專屬應用程式相比,我們的 PWA 使用者採用率大幅提升。

並排比較直接啟動 PWA (左側,速度較快) 與安裝並啟動 Android 應用程式 (右側,速度較慢)。
依平台劃分的交易次數。¡OS:16397 (3.98%)。Android:13769 (3.34%)。網頁:382184 (92.68%)。
大多數交易都是在網路上進行。

深入探討技術

尋找啟用 MishiPay 的商店

如要啟用這項功能,我們需要使用 getCurrentPosition() API,以及以 IP 為基礎的回溯解決方案。

const geoOptions = {
  timeout: 10 * 1000,
  enableHighAccuracy: true,
  maximumAge: 0,
};

window.navigator.geolocation.getCurrentPosition(
  (position) => {
    const cords = position.coords;
    console.log(`Latitude :  ${cords.latitude}`);
    console.log(`Longitude :  ${cords.longitude}`);
  },
  (error) => {
    console.debug(`Error: ${error.code}:${error.message}`);
    /**
     * Invoke the IP based location services
     * to fetch the latitude and longitude of the user.
     */
  },
  geoOptions,
);

這個方法在應用程式的舊版中運作良好,但後來證明是 MishiPay 使用者的巨大痛點,原因如下:

  • IP 備援解決方案的位置資訊不準確。
  • 隨著各區域支援 MishiPay 的商店越來越多,使用者必須捲動清單並找出正確的商店。
  • 使用者有時會不小心選擇錯誤的商店,導致系統記錄的購買交易有誤。

為解決這些問題,我們在每間商店的店內螢幕上嵌入了獨一無二的地理位置 QR code。為更快速的新手上路體驗奠定基礎。使用者掃描商店行銷宣傳品上印製的地理位置 QR code,即可存取「掃描即付」網頁應用程式。這樣一來,他們就不必輸入網址 mishipay.shop 才能存取服務。

使用 PWA 掃描店內商品。

掃描產品

MishiPay 應用程式的核心功能是條碼掃描,因為這項功能可讓使用者掃描自己的購買項目,並在抵達收銀機前查看總計金額。

如要在網路上建構掃描體驗,我們已找出三個核心層。

這張圖表顯示三個主要執行緒層:視訊串流、處理層和解碼器層。

影片串流

藉助 getUserMedia() 方法,我們可以存取使用者的後視鏡頭,但須遵守下列限制。呼叫方法會自動觸發提示,要求使用者接受或拒絕存取攝影機。取得影片串流的存取權後,我們就能將其轉送至影片元素,如下所示:

/**
 * Video Stream Layer
 * https://developer.mozilla.org/docs/Web/API/MediaDevices/getUserMedia
 */
const canvasEle = document.getElementById('canvas');
const videoEle = document.getElementById('videoElement');
const canvasCtx = canvasEle.getContext('2d');
fetchVideoStream();
function fetchVideoStream() {
  let constraints = { video: { facingMode: 'environment' } };
  if (navigator.mediaDevices !== undefined) {
    navigator.mediaDevices
      .getUserMedia(constraints)
      .then((stream) => {
        videoEle.srcObject = stream;
        videoStream = stream;
        videoEle.play();
        // Initiate frame capture - Processing Layer.
      })
      .catch((error) => {
        console.debug(error);
        console.warn(`Failed to access the stream:${error.name}`);
      });
  } else {
    console.warn(`getUserMedia API not supported!!`);
  }
}

處理層

如要在特定影片串流中偵測條碼,我們需要定期擷取影格,並將影格傳輸至解碼器層。如要擷取影格,請使用 Canvas APIdrawImage() 方法,將 VideoElement 的串流繪製到 HTMLCanvasElement 上。

/**
 * Processing Layer - Frame Capture
 * https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Manipulating_video_using_canvas
 */
async function captureFrames() {
  if (videoEle.readyState === videoEle.HAVE_ENOUGH_DATA) {
    const canvasHeight = (canvasEle.height = videoEle.videoHeight);
    const canvasWidth = (canvasEle.width = videoEle.videoWidth);
    canvasCtx.drawImage(videoEle, 0, 0, canvasWidth, canvasHeight);
    // Transfer the `canvasEle` to the decoder for barcode detection.
    const result = await decodeBarcode(canvasEle);
  } else {
    console.log('Video feed not available yet');
  }
}

對於進階用途,這個層也會執行一些預先處理工作,例如裁剪、旋轉或轉換為灰階。這些工作可能會耗用大量 CPU 資源,導致應用程式無法回應,因為條碼掃描是長時間執行的作業。有了 OffscreenCanvas API,我們就能將耗用大量 CPU 資源的工作卸載至網頁工作人員。在支援硬體圖形加速的裝置上,WebGL API 和其 WebGL2RenderingContext 可針對 CPU 密集型前處理工作,最佳化效能增益。

解碼器層

最後一層是解碼器層,負責從處理層擷取的影格解碼條碼。透過 Shape Detection API (尚未在所有瀏覽器上推出),瀏覽器本身會從 ImageBitmapSource 解碼條碼,ImageBitmapSource 可以是 img 元素、SVG image 元素、video 元素、canvas 元素、Blob 物件、ImageData 物件或 ImageBitmap 物件。

這張圖表顯示三個主要執行緒層:影片串流、處理層和 Shape Detection API。

/**
 * Barcode Decoder with Shape Detection API
 * https://web.dev/shape-detection/
 */
async function decodeBarcode(canvas) {
  const formats = [
    'aztec',
    'code_128',
    'code_39',
    'code_93',
    'codabar',
    'data_matrix',
    'ean_13',
    'ean_8',
    'itf',
    'pdf417',
    'qr_code',
    'upc_a',
    'upc_e',
  ];
  const barcodeDetector = new window.BarcodeDetector({
    formats,
  });
  try {
    const barcodes = await barcodeDetector.detect(canvas);
    console.log(barcodes);
    return barcodes.length > 0 ? barcodes[0]['rawValue'] : undefined;
  } catch (e) {
    throw e;
  }
}

對於尚不支援 Shape Detection API 的裝置,我們需要備用解決方案來解碼條碼。Shape Detection API 會公開 getSupportedFormats() 方法,協助在 Shape Detection API 和備援解決方案之間切換。

// Feature detection.
if (!('BarceodeDetector' in window)) {
  return;
}
// Check supported barcode formats.
BarcodeDetector.getSupportedFormats()
.then((supportedFormats) => {
  supportedFormats.forEach((format) => console.log(format));
});

流程圖:視條碼偵測器支援和支援的條碼格式而定,系統會使用 Shape Detection API 或備用解決方案。

備用解決方案

您可以輕鬆整合多個開放原始碼和企業掃描程式庫與任何網路應用程式,以實作掃描功能。以下是 MishiPay 建議的部分程式庫。

程式庫名稱 類型 Wasm 解決方案 條碼格式
QuaggaJs 開放原始碼 1 天
ZxingJs 開放原始碼 1D 和 2D (受限)
CodeCorp Enterprise 1D 和 2D
Scandit Enterprise 1D 和 2D
開放原始碼和商用條碼掃描程式庫比較

這些程式庫都是功能齊全的 SDK,可組成上述所有層。此外,這些 API 也會公開介面,支援各種掃描作業。視業務需求而定,您可選擇 Wasm 或非 Wasm 解決方案,這取決於條碼格式和偵測速度。雖然需要額外資源 (Wasm) 解碼條碼,但 Wasm 解決方案的準確度優於非 Wasm 解決方案。

Scandit 是我們的首選。這項技術支援我們業務用途所需的所有條碼格式,且掃描速度比所有可用的開放原始碼程式庫都快。

掃描技術的未來

一旦所有主要瀏覽器都完全支援 Shape Detection API,我們可能會推出新的 HTML 元素 <scanner>,具備條碼掃描器所需的功能。MishiPay 的工程團隊認為,由於開放原始碼和授權程式庫數量不斷增加,可支援「掃描即走」等體驗,因此條碼掃描功能應成為新的 HTML 元素,具有實際用途。

結論

應用程式疲乏是開發人員在產品上市時會遇到的問題。使用者通常會在下載應用程式前,先瞭解應用程式的價值。在商店中,MishiPay 可節省購物者的時間並提升體驗,因此等待下載應用程式才能使用,就顯得不合邏輯。這時,PWA 就能派上用場。

我們消除了進入門檻,交易量增加了 10 倍,使用者也省下 2.5 年的排隊時間。

特別銘謝

本文由 Joe Medley 審查。