כאן אפשר לקרוא איך המעבר ל-PWA עזר לעסק של MishiPay.
MishiPay מאפשרת לקונים לסרוק ולשלם על הקניות שלהם באמצעות הסמארטפונים שלהם, במקום לבזבז זמן בתור לקופה. באמצעות טכנולוגיית Scan & Go של MishiPay, הקונים יכולים להשתמש בטלפון שלהם כדי לסרוק את הברקוד של הפריטים ולשלם עליהם, ואז לצאת מהחנות. מחקרים מראים שבכל שנה, ההמתנה בתור בחנויות עולה למגזר הקמעונאות העולמי 200 מיליארד דולר.
הטכנולוגיה שלנו מסתמכת על יכולות החומרה של המכשיר, כמו חיישני GPS ומצלמות, שמאפשרות למשתמשים לאתר חנויות שמופעלת בהן MishiPay, לסרוק ברקודים של פריטים בחנות הפיזית ואז לשלם באמצעות אמצעי התשלום הדיגיטלי שבחרו. הגרסאות הראשונות של הטכנולוגיה שלנו Scan & Go היו אפליקציות ספציפיות לפלטפורמות iOS ו-Android, והמשתמשים הראשונים אהבו את הטכנולוגיה. כדאי לקרוא את המשך המאמר כדי להבין איך המעבר ל-PWA הגדיל את מספר העסקאות פי 10 וחסך 2.5 שנים של המתנה בתור!
10×
יותר עסקאות
שנתיים וחצי
התור נשמר
האתגר
המשתמשים שלנו חושבים שהטכנולוגיה שלנו מאוד שימושית כשהם מחכים בתור או בקופה, כי היא מאפשרת להם לדלג על התור וליהנות מחוויה חלקה בחנות. אבל הטרחה שבלהוריד אפליקציה ל-Android או ל-iOS גרמה למשתמשים לא לבחור בטכנולוגיה שלנו למרות הערך שלה. היה קשה יותר ויותר להשתמש ב-MishiPay, והיינו צריכים להגדיל את מספר המשתמשים עם מחסום כניסה נמוך יותר.
פתרון
המאמצים שלנו בפיתוח והשקת ה-PWA עזרו לנו להסיר את הטרחה של ההתקנה, ועודדו משתמשים חדשים לנסות את הטכנולוגיה שלנו בחנות פיזית, לדלג על התור וליהנות מחוויית קנייה חלקה. מאז ההשקה, חלה עלייה משמעותית במספר המשתמשים ב-PWA שלנו בהשוואה לאפליקציות הספציפיות לפלטפורמה.
ניתוח טכני מעמיק
איך מוצאים חנויות שמופעל בהן MishiPay
כדי להפעיל את התכונה הזו, אנחנו מסתמכים על ה-API getCurrentPosition() ועל פתרון חלופי שמבוסס על כתובת 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 ייחודיים עם מיקום גיאוגרפי בתצוגות בחנויות של כל חנות. השינוי הזה סלל את הדרך לחוויית הצטרפות מהירה יותר. המשתמשים סורקים את קודי ה-QR עם המיקום הגיאוגרפי שמודפסים על חומרים שיווקיים בחנויות כדי לגשת לאפליקציית האינטרנט 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!!`);
}
}
שכבת עיבוד
כדי לזהות ברקוד בשידור וידאו נתון, צריך לצלם פריימים מדי פעם ולהעביר אותם לשכבת הפענוח. כדי לצלם פריים, אנחנו מציירים את הסטרימינג מ-VideoElement על HTMLCanvasElement באמצעות ה-method 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. במכשירים שתומכים בהאצת גרפיקה בחומרה, ה-API של WebGL וה-WebGL2RenderingContext שלו יכולים לשפר את הביצועים במשימות עיבוד מקדים שדורשות הרבה משאבים מה-CPU.
שכבת פענוח
השכבה האחרונה היא שכבת המפענח, שאחראית לפענוח ברקודים מהמסגרות שצולמו על ידי שכבת העיבוד. הודות ל-Shape Detection API (שעדיין לא זמין בכל הדפדפנים), הדפדפן עצמו מפענח את הברקוד מ-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;
}
}
למכשירים שלא תומכים עדיין ב-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));
});

פתרון חלופי
יש כמה ספריות סריקה בקוד פתוח וספריות סריקה ארגוניות שאפשר לשלב בקלות עם כל אפליקציית אינטרנט כדי להטמיע סריקה. הנה כמה מהספריות שמומלצות על ידי MishiPay.
כל הספריות האלה הן ערכות SDK מלאות שכוללות את כל השכבות שצוינו. הם גם חושפים ממשקים לתמיכה בפעולות סריקה שונות. בהתאם לפורמטים של הברקודים ולמהירות הזיהוי שנדרשת לתרחיש העסקי, אפשר לבחור בין פתרונות Wasm לבין פתרונות שאינם Wasm. למרות התקורה שנובעת מהצורך במשאב נוסף (Wasm) כדי לפענח את הברקוד, פתרונות Wasm משיגים ביצועים טובים יותר מפתרונות שאינם Wasm מבחינת דיוק.
Scandit הייתה הבחירה העיקרית שלנו. היא תומכת בכל פורמטי הברקוד שנדרשים לתרחישי השימוש העסקיים שלנו, והיא עדיפה על כל הספריות הזמינות בקוד פתוח מבחינת מהירות הסריקה.
העתיד של הסריקה
אחרי שכל הדפדפנים העיקריים יתמכו באופן מלא ב-Shape Detection API, נוכל להוסיף רכיב HTML חדש, <scanner>, עם היכולות הנדרשות לסורק ברקודים. צוות ההנדסה של MishiPay מאמין שיש תרחיש שימוש מוצלח לפונקציונליות של סריקת ברקודים כרכיב HTML חדש, בגלל המספר הגדל של ספריות קוד פתוח וספריות עם רישיון שמאפשרות חוויות כמו סריקה ותשלום ועוד הרבה אחרות.
סיכום
עייפות מאפליקציות היא בעיה שמפתחים נתקלים בה כשהמוצרים שלהם נכנסים לשוק. לפני שהמשתמשים מורידים אפליקציה, הם רוצים להבין מה הערך שהיא תספק להם. בחנות, שבה MishiPay חוסכת לקונים זמן ומשפרת את חוויית הקנייה שלהם, לא הגיוני לחכות להורדה לפני שהם יכולים להשתמש באפליקציה. כאן אפליקציית ה-PWA שלנו עוזרת.
הסרנו את המחסום לכניסה, הגדלנו את מספר העסקאות פי 10 ואיפשרנו למשתמשים לחסוך 2.5 שנים של המתנה בתור.
תודות
המאמר הזה נבדק על ידי Joe Medley.