Узнайте, как переход на PWA помог бизнесу MishiPay.
MishiPay позволяет покупателям сканировать и оплачивать покупки с помощью смартфонов, а не тратить время на ожидание в очереди на кассе. Благодаря технологии Scan & Go от MishiPay покупатели могут использовать свой собственный телефон для сканирования штрихкода на товарах и оплаты, а затем просто покинуть магазин. Исследования показывают, что очереди в магазинах обходятся мировому розничному сектору примерно в 200 миллиардов долларов в год.
Наша технология основана на аппаратных возможностях устройств, таких как датчики GPS и камеры, которые позволяют пользователям находить магазины с поддержкой MishiPay, сканировать штрихкоды товаров в физическом магазине, а затем платить с помощью выбранного ими цифрового платежного метода. Первоначальные версии нашей технологии Scan & Go представляли собой платформенно-зависимые приложения для iOS и Android, и первым пользователям эта технология понравилась. Читайте дальше, чтобы узнать, как переход на PWA увеличил количество транзакций в 10 раз и сэкономил 2,5 года очередей!
10 ×
Увеличение транзакций
2,5 года
Очередь сохранена
Испытание
Пользователи считают нашу технологию чрезвычайно полезной при ожидании в очереди или на кассе, поскольку она позволяет им избежать очереди и получить гладкий опыт в магазине. Но хлопоты по загрузке приложения 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, как показано ниже:
/**
* 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()
API Canvas .
/**
* 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');
}
}
Для расширенных вариантов использования этот уровень также выполняет некоторые задачи предварительной обработки, такие как обрезка, поворот или преобразование в оттенки серого. Эти задачи могут быть ресурсоемкими и приводить к тому, что приложение перестает отвечать, учитывая, что сканирование штрихкода — это длительная операция. С помощью API OffscreenCanvas мы можем переложить ресурсоемкую задачу на веб-работника. На устройствах, поддерживающих аппаратное графическое ускорение, API WebGL и его WebGL2RenderingContext
могут оптимизировать выигрыш в ресурсоемких задачах предварительной обработки.
Декодерный слой
Последний слой — это слой декодера, который отвечает за декодирование штрихкодов из кадров, захваченных слоем обработки. Благодаря API определения формы (который пока доступен не во всех браузерах) браузер сам декодирует штрихкод из ImageBitmapSource
, который может быть элементом img
, элементом image
SVG, элементом 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 был нашим основным выбором. Он поддерживает все форматы штрихкодов, необходимые для наших бизнес-кейсов; он превосходит все доступные библиотеки с открытым исходным кодом по скорости сканирования.
Будущее сканирования
Как только API распознавания формы будет полностью поддерживаться всеми основными браузерами, у нас потенциально может появиться новый элемент HTML <scanner>
, обладающий возможностями, необходимыми для сканера штрихкодов. Инженеры MishiPay считают, что есть веский вариант использования функциональности сканирования штрихкодов в качестве нового элемента HTML из-за растущего числа библиотек с открытым исходным кодом и лицензированных библиотек, которые обеспечивают такие возможности, как Scan & Go и многие другие.
Заключение
Усталость от приложений — это проблема, с которой сталкиваются разработчики, когда их продукты выходят на рынок. Пользователи часто хотят понять ценность, которую приложение им дает, прежде чем они его загрузят. В магазине, где MishiPay экономит время покупателей и улучшает их опыт, нелогично ждать загрузки, прежде чем они смогут использовать приложение. Вот тут-то и помогает наше PWA. Устранив барьер для входа, мы увеличили количество транзакций в 10 раз и позволили нашим пользователям сэкономить 2,5 года ожидания в очереди.
Благодарности
Эту статью рецензировал Джо Медли .