瞭解改用 PWA 後,MishiPay 的業務有何變化。
MishiPay 讓購物者可以用智慧型手機掃描並付款,不必浪費時間排隊結帳。有了 MishiPay 的掃描即走技術,購物者就能使用自己的手機掃描商品條碼並付款,然後直接離開商店。研究顯示,全球零售業每年因店內排隊而損失約 2,000 億美元。
我們的技術仰賴裝置硬體功能,例如 GPS 感應器和相機,讓使用者可以找到支援 MishiPay 的商店、掃描實體商店中的商品條碼,然後使用所選數位付款方式付款。掃描與前往技術的初始版本是針對 iOS 和 Android 平台的應用程式,早期採用者非常喜歡這項技術。請繼續閱讀,瞭解改用 PWA 後,交易量增加了 10 倍,並節省了 2.5 年的排隊時間!
10×
交易量增加
2.5 年
已儲存排隊功能
挑戰
使用者在排隊或結帳時,會發現我們的技術非常實用,因為這項技術可讓他們略過排隊,享有順暢的店內體驗。但由於下載 Android 或 iOS 應用程式相當麻煩,因此使用者即使認為我們的技術很有價值,也不會選擇採用。這對 MishiPay 來說是一項日益嚴峻的挑戰,因此我們需要降低使用門檻,提高使用者採用率。
解決方案
我們努力建構及推出 PWA,不僅可免除安裝麻煩,還能鼓勵新使用者在實體商店中試用我們的技術,省去排隊等候的時間,享受無縫的購物體驗。自推出以來,與特定平台應用程式相比,使用者採用 PWA 的比例大幅增加。
深入探討技術
尋找支援 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,即可存取 Scan & Go 網頁應用程式。這樣一來,使用者就不必輸入網址 mishipay.shop
就能存取服務。
掃描產品
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 API 的 drawImage()
方法,將 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 密集的預處理工作中,提升效益。
解碼器層
最後一個層級是解碼器層,負責從處理層擷取的影格中解碼條碼。多虧形狀偵測 API (目前尚未在所有瀏覽器上提供),瀏覽器本身會從 ImageBitmapSource
解碼條碼,ImageBitmapSource
可以是 img
元素、SVG image
元素、video
元素、canvas
元素、Blob
物件、ImageData
物件或 ImageBitmap
物件。
/**
* 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;
}
}
對於尚不支援形狀偵測 API 的裝置,我們需要備用解碼條碼的解決方案。形狀偵測 API 會公開 getSupportedFormats()
方法,協助您在形狀偵測 API 和備用解決方案之間切換。
// Feature detection.
if (!('BarceodeDetector' in window)) {
return;
}
// Check supported barcode formats.
BarcodeDetector.getSupportedFormats()
.then((supportedFormats) => {
supportedFormats.forEach((format) => console.log(format));
});
備用解決方案
您可以使用多個開放原始碼和企業掃描程式庫,輕鬆將其與任何網路應用程式整合,以便實作掃描作業。以下是 MishiPay 推薦的部分程式庫。
上述所有程式庫都是完整的 SDK,可組成上述所有層級。並公開介面,支援各種掃描作業。視業務需求所需的條碼格式和偵測速度而定,您可以選擇使用 Wasm 或非 Wasm 解決方案。雖然需要額外資源 (Wasm) 來解碼條碼,但 Wasm 解決方案在準確度方面優於非 Wasm 解決方案。
我們主要選擇 Scandit。這項工具支援所有業務用途所需的條碼格式,在掃描速度方面勝過所有可用的開放原始碼程式庫。
掃描的未來
一旦所有主要瀏覽器都完全支援 Shape Detection API,我們可能就會擁有新的 HTML 元素 <scanner>
,其中包含條碼掃描器所需的功能。MishiPay 的工程團隊認為,由於開放原始碼和授權程式庫的數量不斷增加,可提供「掃描並前往」等體驗,因此條碼掃描功能確實適合作為新的 HTML 元素。
結論
開發人員在產品進入市場時,可能會遇到應用程式疲勞的問題。使用者通常會在下載應用程式前,先瞭解應用程式提供的價值。在商店中,MishiPay 可為購物者省下時間並改善體驗,因此如果購物者必須等待下載作業完成才能使用應用程式,這就違反直覺。這正是 PWA 發揮作用的地方。我們消除了進入門檻,交易量因此增加了 10 倍,使用者也能省下 2.5 年的等待時間。
特別銘謝
本文由 Joe Medley 審查。