Dowiedz się, jak przejście na PWA pomogło firmie MishiPay.
MishiPay umożliwia kupującym skanowanie i płacenie za zakupy za pomocą smartfonów, dzięki czemu nie muszą tracić czasu na stanie w kolejce do kasy. Dzięki technologii Skanuj i kup firmy MishiPay klienci mogą zeskanować kod kreskowy produktów za pomocą telefonu i opłacić je, a potem po prostu wyjść ze sklepu. Badania pokazują, że kolejki w sklepach kosztują globalny sektor handlu detalicznego około 200 mld USD rocznie.
Nasza technologia opiera się na możliwościach sprzętowych urządzenia, takich jak czujniki GPS i kamery, które umożliwiają użytkownikom znajdowanie sklepów obsługujących MishiPay, skanowanie kodów kreskowych produktów w sklepie stacjonarnym, a następnie płacenie za pomocą wybranej formy płatności cyfrowej. Początkowe wersje technologii Skanuj i jedź były aplikacjami na iOS i Androida. Na początku spodobały się one użytkownikom. Przeczytaj artykuł, aby dowiedzieć się, jak przejście na PWA zwiększyło liczbę transakcji 10-krotnie i zaoszczędziło 2,5 roku oczekiwania w kolejce.
10×
Wzrost liczby transakcji
2,5 roku
Zapisywanie w kolejce
Wyzwanie
Użytkownicy uważają, że nasza technologia jest bardzo przydatna, gdy czekają w kolejce lub przy kasie, ponieważ pozwala im pominąć kolejkę i płynnie poruszać się po sklepie. Jednak konieczność pobrania aplikacji na Androida lub iOS sprawiła, że użytkownicy nie wybrali naszej technologii, mimo że była ona wartościowa. Było to coraz większe wyzwanie dla MishiPay, ponieważ musieliśmy zwiększyć liczbę użytkowników przy jednoczesnym obniżeniu progu wejścia.
Rozwiązanie
Dzięki wysiłkom włożonym w stworzenie i uruchomienie aplikacji internetowej udało nam się wyeliminować problemy związane z instalacją. Zachęciliśmy nowych użytkowników do wypróbowania naszej technologii w sklepie stacjonarnym, pominięcia kolejki i skorzystania z bezproblemowego procesu zakupowego. Od momentu uruchomienia aplikacji odnotowaliśmy gwałtowny wzrost liczby użytkowników korzystających z naszej aplikacji internetowej w porównaniu z użytkownikami aplikacji na poszczególne platformy.
Szczegóły techniczne
Znajdowanie sklepów obsługujących MishiPay
Aby włączyć tę funkcję, korzystamy z interfejsu API getCurrentPosition()
oraz rozwiązania zapasowego opartego na adresie 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,
);
Takie podejście sprawdzało się w wcześniejszych wersjach aplikacji, ale później okazało się, że jest bardzo uciążliwe dla użytkowników MishiPay z tych powodów:
- niedokładne lokalizacje w przypadku rozwiązań zapasowych opartych na adresie IP;
- Wzrost liczby sklepów obsługujących MishiPay w poszczególnych regionach wymaga od użytkowników przewijania listy i identyfikowania właściwego sklepu.
- Użytkownicy czasami przypadkowo wybierają niewłaściwy sklep, przez co zakupy są rejestrowane nieprawidłowo.
Aby rozwiązać te problemy, w ramach każdego sklepu umieściliśmy na wyświetlaczach w sklepie stacjonarnym unikalne kody QR z lokalizacją. Dzięki temu proces wprowadzania do korzystania z usługi jest szybszy. Użytkownicy skanują kody QR zlokalizowane geograficznie, wydrukowane na materiałach marketingowych w sklepach, aby uzyskać dostęp do aplikacji internetowej Skanuj i idź.
Dzięki temu nie muszą wpisywać adresu internetowego mishipay.shop
, aby uzyskać dostęp do usługi.
Skanowanie produktów
Podstawową funkcją aplikacji MishiPay jest skanowanie kodów kreskowych, ponieważ umożliwia użytkownikom skanowanie własnych zakupów i sprawdzanie łącznej kwoty jeszcze przed dotarciem do kasy.
Aby stworzyć narzędzie do skanowania stron internetowych, zidentyfikowaliśmy 3 podstawowe warstwy.
Strumień wideo
Za pomocą metody getUserMedia()
możemy uzyskać dostęp do tylnej kamery użytkownika z ograniczeniami wymienionymi poniżej. Wywołanie tej metody automatycznie powoduje wyświetlenie użytkownikowi prośby o przyznanie lub odmowę dostępu do aparatu. Gdy uzyskamy dostęp do strumienia wideo, możemy go przekazać do elementu wideo, jak pokazano poniżej:
/**
* 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!!`);
}
}
Warstwa przetwarzania
Aby wykryć kod kreskowy w danym strumieniu wideo, musimy okresowo przechwytywać klatki i przesyłać je do warstwy dekodera. Aby uchwycić kadr, po prostu rysujemy strumień z VideoElement
na HTMLCanvasElement
za pomocą metody drawImage()
interfejsu 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');
}
}
W zaawansowanych zastosowaniach warstwa ta wykonuje też niektóre zadania wstępnego przetwarzania, takie jak przycinanie, obracanie czy konwersja na skalę szarości. Te zadania mogą być wymagające pod względem procesora i mogą spowodować, że aplikacja przestanie odpowiadać, ponieważ skanowanie kodów kreskowych to długotrwała operacja. Za pomocą interfejsu OffscreenCanvas możemy przekazać zadanie mocno angażujące procesor do web workera. Na urządzeniach, które obsługują akcelerację graficzną sprzętową, interfejs WebGL API i WebGL2RenderingContext
mogą optymalizować korzyści płynące z zadań wstępnych wymagających dużej mocy obliczeniowej procesora.
Warstwa dekodera
Ostatnią warstwą jest warstwa dekodera, która odpowiada za dekodowanie kodów kreskowych z klatek przechwycionych przez warstwę przetwarzania. Dzięki interfejsowi Shape Detection API (który nie jest jeszcze dostępny we wszystkich przeglądarkach) przeglądarka sama dekoduje kod kreskowy z elementu ImageBitmapSource
, który może być elementem img
, image
, video
, canvas
, obiektem Blob
, ImageData
lub 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;
}
}
W przypadku urządzeń, które nie obsługują jeszcze interfejsu Shape Detection API, potrzebujemy rozwiązania zapasowego do dekodowania kodów kreskowych. Interfejs Shape Detection API udostępnia metodę getSupportedFormats()
, która ułatwia przełączanie się między interfejsem Shape Detection API a rozwiązaniem zapasowym.
// Feature detection.
if (!('BarceodeDetector' in window)) {
return;
}
// Check supported barcode formats.
BarcodeDetector.getSupportedFormats()
.then((supportedFormats) => {
supportedFormats.forEach((format) => console.log(format));
});
Rozwiązanie awaryjne
Dostępnych jest kilka bibliotek skanowania open source i firmowych, które można łatwo zintegrować z dowolną aplikacją internetową, aby wdrożyć skanowanie. Oto niektóre z bibliotek rekomendowanych przez MishiPay.
Wszystkie wymienione powyżej biblioteki to pełne pakiety SDK, które zawierają wszystkie opisane wyżej warstwy. Zapewniają też interfejsy do obsługi różnych operacji skanowania. W zależności od formatu kodu kreskowego i szybkości wykrywania potrzebnej w przypadku biznesowym możesz wybrać rozwiązanie Wasm lub inne rozwiązanie. Pomimo konieczności użycia dodatkowego zasobu (Wasm) do dekodowania kodu kreskowego, rozwiązania Wasm wygrywają z rozwiązaniami bez Wasm pod względem dokładności.
Naszym głównym wyborem było Scandit. Obsługuje wszystkie formaty kodów kreskowych wymagane w przypadku zastosowań biznesowych; pod względem szybkości skanowania przewyższa wszystkie dostępne biblioteki open source.
Przyszłość skanowania
Gdy interfejs Shape Detection API będzie w pełni obsługiwany przez wszystkie główne przeglądarki, możemy wprowadzić nowy element HTML <scanner>
, który będzie miał funkcje wymagane do skanowania kodów kreskowych. Zespół inżynierów w MishiPay uważa, że skanowanie kodów kreskowych może być przydatną funkcją w ramach nowego elementu HTML ze względu na rosnącą liczbę bibliotek open source i licencjonowanych, które umożliwiają korzystanie z funkcji takich jak skanowanie i wyjście oraz wielu innych.
Podsumowanie
Zmęczenie aplikacjami to problem, z którym deweloperzy mierzą się, gdy ich produkty wchodzą na rynek. Użytkownicy często chcą zrozumieć, co daje im aplikacja, zanim ją pobiorą. W sklepie, w którym aplikacja MishiPay pozwala oszczędzać czas kupujących i poprawia ich wrażenia, nielogiczne jest czekanie na pobranie aplikacji przed jej użyciem. Właśnie w tym przypadku przydatne są strony internetowe oparte na aplikacji internetowej. Dzięki usunięciu bariery wejścia liczba naszych transakcji wzrosła 10-krotnie, a użytkownicy zaoszczędzili 2,5 roku oczekiwania w kolejce.
Podziękowania
Ten artykuł został sprawdzony przez Joe Medley.