Hier erfahren Sie, wie MishiPay von der Umstellung auf eine PWA profitiert hat.
Mit MishiPay können Käufer ihre Einkäufe mit ihrem Smartphone scannen und bezahlen, anstatt Zeit in der Schlange an der Kasse zu verschwenden. Mit der Scan & Go-Technologie von MishiPay können Käufer mit ihrem eigenen Smartphone den Barcode der Artikel scannen, bezahlen und dann einfach den Laden verlassen. Studien zeigen, dass Warteschlangen in Geschäften den weltweiten Einzelhandel jährlich etwa 200 Milliarden $kosten.
Unsere Technologie basiert auf Gerätehardwarefunktionen wie GPS-Sensoren und Kameras, mit denen Nutzer MishiPay-kompatible Geschäfte finden, Artikelbarcodes im Geschäft scannen und dann mit der digitalen Zahlungsmethode ihrer Wahl bezahlen können. Die ersten Versionen unserer Scan & Go-Technologie waren plattformspezifische iOS- und Android-Anwendungen, die bei den frühen Nutzern sehr beliebt waren. Lesen Sie weiter, um zu erfahren, wie durch die Umstellung auf eine PWA die Anzahl der Transaktionen um das Zehnfache gesteigert und eine Wartezeit von 2,5 Jahren vermieden wurde.
10×
Mehr Transaktionen
2,5 Jahre
Eingelagerte Videos
Herausforderung
Nutzer finden unsere Technologie äußerst hilfreich, wenn sie in einer Warteschlange oder an der Kasse warten, da sie die Warteschlange überspringen und problemlos einkaufen können. Aufgrund des Aufwands, eine Android- oder iOS-App herunterzuladen, haben Nutzer unsere Technologie trotz des Mehrwerts nicht ausgewählt. Das war eine wachsende Herausforderung für MishiPay. Wir mussten die Nutzerakzeptanz durch eine niedrigere Einstiegsbarriere steigern.
Lösung
Durch die Entwicklung und Einführung der PWA konnten wir die Installation vereinfachen und neue Nutzer dazu anregen, unsere Technologie in einem Geschäft auszuprobieren, die Warteschlange zu überspringen und nahtlos einzukaufen. Seit der Einführung haben wir eine enorme Steigerung der Nutzerakzeptanz unserer PWA im Vergleich zu unseren plattformspezifischen Anwendungen verzeichnet.
Technische Details
MishiPay-kompatible Geschäfte finden
Für diese Funktion nutzen wir die getCurrentPosition()
API und eine IP-basierte Fallback-Lösung.
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,
);
Dieser Ansatz funktionierte in den früheren Versionen der App gut, stellte sich aber später aus folgenden Gründen als großer Nachteil für die Nutzer von MishiPay heraus:
- Standortabweichungen bei den IP-basierten Fallback-Lösungen
- Aufgrund der wachsenden Liste der MishiPay-kompatiblen Geschäfte pro Region müssen Nutzer durch eine Liste scrollen und das richtige Geschäft finden.
- Nutzer wählen gelegentlich versehentlich das falsche Geschäft aus, wodurch die Käufe falsch erfasst werden.
Um diese Probleme zu beheben, haben wir in den Geschäften eindeutige QR-Codes mit Standortinformationen auf den Displays eingebettet. So konnte das Onboarding beschleunigt werden. Nutzer scannen einfach die auf den Marketingmaterialien in den Geschäften gedruckten geolokalisierten QR-Codes, um auf die Scan & Go-Webanwendung zuzugreifen.
So muss er nicht mehr die Webadresse mishipay.shop
eingeben, um auf den Dienst zuzugreifen.
Produkte scannen
Eine zentrale Funktion der MishiPay App ist das Scannen von Barcodes, da Nutzer so ihre eigenen Einkäufe scannen und den aktuellen Gesamtbetrag sehen können, noch bevor sie an der Kasse angekommen sind.
Für die Entwicklung eines Web-Scantools haben wir drei Hauptebenen identifiziert.
Videostream
Mithilfe der Methode getUserMedia()
können wir unter den unten aufgeführten Einschränkungen auf die Rückkamera des Nutzers zugreifen. Wenn Sie die Methode aufrufen, werden Nutzer automatisch aufgefordert, den Zugriff auf ihre Kamera zuzulassen oder abzulehnen. Sobald wir Zugriff auf den Videostream haben, können wir ihn an ein Videoelement weiterleiten, wie unten dargestellt:
/**
* 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!!`);
}
}
Verarbeitungsschicht
Um einen Barcode in einem bestimmten Videostream zu erkennen, müssen wir regelmäßig Frames erfassen und an die Dekodierungsebene übertragen. Um einen Frame zu erfassen, zeichnen wir die Streams von VideoElement
einfach mit der Methode drawImage()
der Canvas API auf eine 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');
}
}
Bei erweiterten Anwendungsfällen führt diese Ebene auch einige Vorverarbeitungsaufgaben aus, z. B. Zuschneiden, Drehen oder Umwandlung in Graustufen. Diese Aufgaben können CPU-intensiv sein und dazu führen, dass die Anwendung nicht mehr reagiert, da das Barcode-Scannen ein langwieriger Vorgang ist. Mithilfe der OffscreenCanvas API können wir die CPU-intensive Aufgabe an einen Webworker auslagern. Auf Geräten, die die hardwaregestützte Grafikbeschleunigung unterstützen, können die WebGL API und ihre WebGL2RenderingContext
die Leistung bei CPU-intensiven Vorverarbeitungsaufgaben optimieren.
Decoderebene
Die letzte Schicht ist die Dekodierungsschicht, die für die Dekodierung von Barcodes aus den Frames verantwortlich ist, die von der Verarbeitungsschicht erfasst wurden. Dank der Shape Detection API (die noch nicht in allen Browsern verfügbar ist) decodiert der Browser selbst den Barcode aus einem ImageBitmapSource
. Das kann ein img
-Element, ein SVG-image
-Element, ein video
-Element, ein canvas
-Element, ein Blob
-Objekt, ein ImageData
-Objekt oder ein ImageBitmap
-Objekt sein.
/**
* 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;
}
}
Für Geräte, die die Shape Detection API noch nicht unterstützen, benötigen wir eine Fallback-Lösung zum Decodieren der Barcodes. Die Shape Detection API stellt die Methode getSupportedFormats()
bereit, mit der Sie zwischen der Shape Detection API und der Fallback-Lösung wechseln können.
// Feature detection.
if (!('BarceodeDetector' in window)) {
return;
}
// Check supported barcode formats.
BarcodeDetector.getSupportedFormats()
.then((supportedFormats) => {
supportedFormats.forEach((format) => console.log(format));
});
Fallback-Lösung
Es gibt mehrere Open-Source- und Unternehmens-Scanbibliotheken, die sich leicht in jede Webanwendung einbinden lassen, um das Scannen zu implementieren. Hier sind einige der Bibliotheken, die MishiPay empfiehlt.
Alle oben genannten Bibliotheken sind vollwertige SDKs, die alle oben genannten Schichten enthalten. Außerdem stellen sie Schnittstellen bereit, um verschiedene Scanvorgänge zu unterstützen. Je nach den Barcodeformaten und der für den Anwendungsfall erforderlichen Erkennungsgeschwindigkeit kann eine Entscheidung zwischen Wasm- und Nicht-Wasm-Lösungen getroffen werden. Trotz des Overheads, der durch eine zusätzliche Ressource (Wasm) zum Decodieren des Barcodes entsteht, sind Wasm-Lösungen in Bezug auf die Genauigkeit besser als Lösungen ohne Wasm.
Scandit war unsere erste Wahl. Sie unterstützt alle Barcodeformate, die für unsere Geschäftsanwendungen erforderlich sind, und ist bei der Scangeschwindigkeit schneller als alle verfügbaren Open-Source-Bibliotheken.
Die Zukunft des Scannens
Sobald die Shape Detection API von allen gängigen Browsern vollständig unterstützt wird, könnten wir ein neues HTML-Element <scanner>
mit den Funktionen für einen Barcodescanner einführen. Die Entwickler von MishiPay sind der Meinung, dass die Barcode-Scanfunktion aufgrund der wachsenden Anzahl von Open-Source- und lizenzierten Bibliotheken, die Funktionen wie „Scannen und gehen“ und viele andere ermöglichen, ein solides Anwendungsbeispiel für ein neues HTML-Element ist.
Fazit
App-Müdigkeit ist ein Problem, mit dem Entwickler konfrontiert sind, wenn ihre Produkte auf den Markt kommen. Nutzer möchten oft wissen, welchen Nutzen eine App bietet, bevor sie sie herunterladen. In einem Geschäft, in dem Käufer mit MishiPay Zeit sparen und die Nutzung der App angenehmer ist, ist es nicht sinnvoll, auf einen Download zu warten, bevor sie eine App verwenden können. Hier kommt unsere PWA ins Spiel. Durch die Beseitigung der Einstiegsbarriere haben wir die Anzahl der Transaktionen verzehnfacht und unseren Nutzern 2, 5 Jahre Wartezeit erspart.
Danksagungen
Dieser Artikel wurde von Joe Medley überprüft.