PWA ของ MishiPay เพิ่มการทำธุรกรรมขึ้น 10 เท่าและช่วยประหยัดเวลาในการจัดคิว 2.5 ปี

ดูว่าการเปลี่ยนไปใช้ PWA ส่งผลต่อธุรกิจของ MishiPay อย่างไร

MishiPay ช่วยให้ผู้เลือกซื้อสแกนและชำระเงินสำหรับการช็อปปิ้งด้วยสมาร์ทโฟนได้โดยไม่ต้องเสียเวลาต่อคิวที่จุดชำระเงิน เทคโนโลยี Scan & Go ของ MishiPay ช่วยให้ผู้เลือกซื้อสามารถใช้โทรศัพท์ของตนเองเพื่อสแกนบาร์โค้ดของสินค้าและชำระเงิน จากนั้นออกจากร้านค้าได้ การศึกษาพบว่าการต่อคิวที่ร้านค้าทำให้ภาคค้าปลีกทั่วโลกสูญเสียรายได้ประมาณ 6.6 ล้านล้านบาทต่อปี

เทคโนโลยีของเราอาศัยความสามารถของฮาร์ดแวร์อุปกรณ์ เช่น เซ็นเซอร์ 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 ในแต่ละภูมิภาคมีจำนวนเพิ่มขึ้นเรื่อยๆ ทำให้ผู้ใช้ต้องเลื่อนดูรายการและระบุร้านค้าที่ถูกต้อง
  • บางครั้งผู้ใช้อาจเลือกร้านค้าที่ไม่ถูกต้องโดยไม่ตั้งใจ ซึ่งทําให้ระบบบันทึกการซื้ออย่างไม่ถูกต้อง

ในการแก้ไขปัญหาเหล่านี้ เราได้ฝังคิวอาร์โค้ดที่ระบุตำแหน่งทางภูมิศาสตร์ที่ไม่ซ้ำกันไว้ในจอแสดงผลในร้านค้าของร้านค้าแต่ละแห่ง ซึ่งปูทางให้ประสบการณ์การเริ่มต้นใช้งานรวดเร็วขึ้น ผู้ใช้เพียงสแกนคิวอาร์โค้ดที่ระบุตำแหน่งทางภูมิศาสตร์ซึ่งพิมพ์ไว้บนสื่อการตลาดที่แสดงในร้านค้าเพื่อเข้าถึงเว็บแอปพลิเคชัน "สแกนแล้วจ่าย" วิธีนี้จะช่วยให้ผู้ใช้ไม่ต้องพิมพ์ที่อยู่เว็บ mishipay.shop เพื่อเข้าถึงบริการ

ประสบการณ์การสแกนในร้านค้าโดยใช้ PWA

การสแกนผลิตภัณฑ์

ฟีเจอร์หลักในแอป MishiPay คือการสแกนบาร์โค้ด เนื่องจากช่วยให้ผู้ใช้สแกนการซื้อของตนเองและดูยอดรวมได้ก่อนที่จะไปที่จุดชำระเงิน

เราได้ระบุเลเยอร์หลัก 3 เลเยอร์เพื่อสร้างประสบการณ์การสแกนในเว็บ

แผนภาพแสดงเลเยอร์เทรดหลัก 3 เลเยอร์ ได้แก่ สตรีมวิดีโอ เลเยอร์การประมวลผล และเลเยอร์โปรแกรมถอดรหัส

สตรีมวิดีโอ

การใช้เมธอด 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!!`);
  }
}

เลเยอร์การประมวลผล

หากต้องการตรวจหาบาร์โค้ดในสตรีมวิดีโอหนึ่งๆ เราจะต้องจับเฟรมเป็นระยะๆ และโอนไปยังเลเยอร์ตัวถอดรหัส หากต้องการจับเฟรม เราเพียงวาดสตรีมจาก VideoElement ไปยัง HTMLCanvasElement โดยใช้เมธอด drawImage() ของ Canvas API

/**
 * 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 มากไปยัง Web Worker ได้ ในอุปกรณ์ที่รองรับการเร่งความเร็วกราฟิกด้วยฮาร์ดแวร์ WebGL2RenderingContext ของ WebGL API จะเพิ่มประสิทธิภาพของงานเตรียมการก่อนประมวลผลที่ต้องใช้ CPU มาก

เลเยอร์ตัวถอดรหัส

ชั้นสุดท้ายคือชั้นตัวถอดรหัส ซึ่งมีหน้าที่ถอดรหัสบาร์โค้ดจากเฟรมที่ชั้นการประมวลผลจับภาพไว้ เบราว์เซอร์จะถอดรหัสบาร์โค้ดจาก ImageBitmapSource ได้ด้วย Shape Detection API (ซึ่งยังไม่พร้อมใช้งานในบางเบราว์เซอร์) ซึ่งอาจเป็นองค์ประกอบ img, องค์ประกอบ SVG image, องค์ประกอบ video, องค์ประกอบ canvas, ออบเจ็กต์ Blob, ออบเจ็กต์ ImageData หรือออบเจ็กต์ ImageBitmap

แผนภาพแสดงเลเยอร์เทรดหลัก 3 เลเยอร์ ได้แก่ สตรีมวิดีโอ เลเยอร์การประมวลผล และ 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 โอเพนซอร์ส ไม่ 1 มิติและ 2 มิติ (จํากัด)
CodeCorp Enterprise ใช่ 1 มิติและ 2 มิติ
Scandit Enterprise ใช่ 1 มิติและ 2 มิติ
การเปรียบเทียบไลบรารีการสแกนบาร์โค้ดแบบโอเพนซอร์สและเชิงพาณิชย์

ไลบรารีทั้งหมดข้างต้นเป็น SDK ที่สมบูรณ์ซึ่งประกอบไปด้วยเลเยอร์ทั้งหมดที่กล่าวถึงข้างต้น และยังแสดงอินเทอร์เฟซเพื่อรองรับการดำเนินการสแกนต่างๆ ด้วย การตัดสินใจอาจใช้โซลูชัน Wasm หรือโซลูชันที่ไม่ใช่ Wasm ทั้งนี้ขึ้นอยู่กับรูปแบบบาร์โค้ดและความเร็วในการตรวจจับที่จำเป็นสำหรับกรณีธุรกิจ แม้ว่าจะต้องใช้ทรัพยากรเพิ่มเติม (Wasm) เพื่อถอดรหัสบาร์โค้ด แต่โซลูชัน Wasm ก็ยังมีประสิทธิภาพเหนือกว่าโซลูชันที่ไม่ใช่ Wasm ในแง่ของความแม่นยำ

Scandit เป็นตัวเลือกหลักของเรา โดยรองรับรูปแบบบาร์โค้ดทั้งหมดที่จําเป็นสําหรับกรณีการใช้งานทางธุรกิจของเรา และเร็วกว่าไลบรารีโอเพนซอร์สทั้งหมดที่มี

อนาคตของการสแกน

เมื่อเบราว์เซอร์หลักทั้งหมดรองรับ Shape Detection API อย่างเต็มรูปแบบแล้ว เราอาจมีองค์ประกอบ HTML ใหม่ <scanner> ที่มีความสามารถที่จำเป็นสำหรับเครื่องสแกนบาร์โค้ด ทีมวิศวกรของ MishiPay เชื่อว่าฟังก์ชันการสแกนบาร์โค้ดควรเป็นองค์ประกอบ HTML ใหม่ เนื่องจากมีไลบรารีโอเพนซอร์สและไลบรารีที่ได้รับอนุญาตจำนวนมากที่เปิดโอกาสให้ผู้ใช้ได้รับประสบการณ์การใช้งาน เช่น สแกนแล้วจ่าย และอื่นๆ อีกมากมาย

บทสรุป

ความเบื่อหน่ายของแอปเป็นปัญหาที่นักพัฒนาแอปต้องเผชิญเมื่อผลิตภัณฑ์ของตนเข้าสู่ตลาด ผู้ใช้มักต้องการเข้าใจคุณค่าที่แอปพลิเคชันมอบให้ก่อนที่จะดาวน์โหลด ในร้านค้าที่ MishiPay ช่วยประหยัดเวลาของผู้เลือกซื้อและปรับปรุงประสบการณ์ของผู้เลือกซื้อ การต้องรอดาวน์โหลดแอปพลิเคชันก่อนจึงจะใช้แอปพลิเคชันได้นั้นขัดกับความรู้สึกของผู้เลือกซื้อ PWA ของเราจะช่วยแก้ปัญหานี้ การยกเลิกข้อจำกัดในการเข้าร่วมทำให้ธุรกรรมเพิ่มขึ้น 10 เท่าและช่วยให้ผู้ใช้ไม่ต้องรอคิวนานถึง 2.5 ปี

ขอขอบคุณ

บทความนี้ผ่านการตรวจสอบโดย Joe Medley