Saiba como a mudança para PWAs ajudou a MishiPay.
A MishiPay permite que os compradores digitalizem e paguem as compras com smartphones, em vez de perder tempo na fila do caixa. Com a tecnologia Scan & Go da MishiPay, os compradores podem usar o próprio smartphone para ler o código de barras dos itens e pagar por eles, depois sair da loja. Estudos revelam que, anualmente, as filas nas lojas custam US $200 bilhões ao setor de varejo global.
Nossa tecnologia depende de recursos de hardware do dispositivo, como sensores de GPS e câmeras, que permitem aos usuários localizar lojas compatíveis com o MishiPay, digitalizar códigos de barras de itens na loja física e pagar usando a forma de pagamento digital de preferência. As versões iniciais da nossa tecnologia Scan & Go eram aplicativos específicos para iOS e Android, e os primeiros usuários adoraram a tecnologia. Leia para saber como a mudança para um PWA aumentou as transações em 10 vezes e economizou 2,5 anos de espera!
10×
Mais transações
2,5 anos
Fila salva
Desafio
Os usuários acham nossa tecnologia extremamente útil ao esperar em uma fila ou no caixa, já que ela permite pular a fila e ter uma experiência tranquila na loja. Mas o trabalho de baixar um aplicativo Android ou iOS fez com que os usuários não escolhessem nossa tecnologia, apesar do valor. Era um desafio crescente para a MishiPay, e precisávamos aumentar a adoção pelos usuários com uma barreira de entrada menor.
Solução
Nossos esforços para criar e lançar o PWA ajudaram a remover o incômodo da instalação e incentivaram novos usuários a testar nossa tecnologia em uma loja física, pular a fila e ter uma experiência de compra integrada. Desde o lançamento, notamos um aumento enorme na adoção da PWA em comparação com nossos aplicativos específicos da plataforma.
Aprofundamento técnico
Como encontrar lojas com MishiPay
Para ativar esse recurso, usamos a
API getCurrentPosition()
junto com uma solução alternativa baseada em 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,
);
Essa abordagem funcionou bem nas versões anteriores do app, mas depois foi comprovada como um grande problema para os usuários da MishiPay pelos seguintes motivos:
- Imprecisões de localização nas soluções de substituição baseadas em IP.
- Uma lista crescente de lojas habilitadas para MishiPay por região exige que os usuários rolem uma lista e identifiquem a loja correta.
- Os usuários às vezes escolhem a loja errada por acidente, o que faz com que as compras sejam registradas incorretamente.
Para resolver esses problemas, incorporamos QR codes geolocalizados exclusivos nos displays de cada loja. Isso abriu caminho para uma experiência de integração mais rápida. Os usuários leem os QR codes geolocalizados impressos em materiais de marketing nas lojas para acessar o web app Scan & Go.
Assim, eles não precisam digitar o endereço da Web mishipay.shop para acessar o serviço.
Digitalizar produtos
Um recurso principal do app MishiPay é a leitura de código de barras, que permite aos usuários ler as próprias compras e ver o total em andamento antes mesmo de chegar a um caixa.
Para criar uma experiência de leitura na Web, identificamos três camadas principais.

Stream de vídeo
Com a ajuda do método
getUserMedia(), podemos
acessar a câmera traseira do usuário com as restrições listadas abaixo. A invocação do método
aciona automaticamente uma solicitação para que os usuários aceitem ou neguem o acesso à câmera. Depois de ter acesso ao stream de vídeo, podemos retransmiti-lo para um elemento de vídeo, conforme mostrado abaixo:
/**
* 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!!`);
}
}
Camada de processamento
Para detectar um código de barras em um determinado fluxo de vídeo, precisamos capturar frames periodicamente e transferi-los para a camada de decodificação. Para capturar um frame, extraímos os fluxos de VideoElement para
um HTMLCanvasElement usando o método
drawImage()
da 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');
}
}
Para casos de uso avançados, essa camada também realiza algumas tarefas de pré-processamento, como corte, rotação ou conversão para escala de cinza. Essas tarefas podem exigir muito da CPU e fazer com que o aplicativo
não responda, já que a leitura de código de barras é uma operação de longa duração. Com a ajuda da API OffscreenCanvas, podemos descarregar a tarefa com uso intensivo de CPU para um service worker da Web. Em dispositivos compatíveis com aceleração gráfica de hardware, a API WebGL e seu
WebGL2RenderingContext podem
otimizar os ganhos nas tarefas de pré-processamento que exigem muito da CPU.
Camada de decodificador
A camada final é o decodificador, responsável por decodificar códigos de barras dos frames
capturados pela camada de processamento. Graças à API Shape Detection (ainda não disponível em todos os navegadores), o próprio navegador decodifica o código de barras de um ImageBitmapSource, que pode ser um elemento img, um elemento SVG image, um elemento video, um elemento canvas, um objeto Blob, um objeto ImageData ou um objeto 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;
}
}
Para dispositivos que ainda não são compatíveis com a API Shape Detection, precisamos de uma solução alternativa para decodificar
os códigos de barras. A API Shape Detection expõe um método
getSupportedFormats()
que ajuda a alternar entre a API Shape Detection e a solução substituta.
// Feature detection.
if (!('BarceodeDetector' in window)) {
return;
}
// Check supported barcode formats.
BarcodeDetector.getSupportedFormats()
.then((supportedFormats) => {
supportedFormats.forEach((format) => console.log(format));
});

Solução substituta
Há várias bibliotecas de verificação de código aberto e empresariais disponíveis que podem ser facilmente integradas a qualquer aplicativo da Web para implementar a verificação. Estas são algumas das bibliotecas recomendadas pela MishiPay.
Todas essas bibliotecas são SDKs completos que compõem todas as camadas discutidas. Elas também expõem interfaces para oferecer suporte a várias operações de verificação. Dependendo dos formatos de código de barras e da velocidade de detecção necessária para o caso de uso, a decisão pode ser entre soluções Wasm e não Wasm. Apesar da sobrecarga de exigir um recurso extra (Wasm) para decodificar o código de barras, as soluções Wasm têm melhor desempenho do que a solução não Wasm em termos de precisão.
A Scandit foi nossa principal escolha. Ele oferece suporte a todos os formatos de código de barras necessários para nossos casos de uso comerciais e supera todas as bibliotecas de código aberto disponíveis em velocidade de leitura.
O futuro da digitalização
Quando a API Shape Detection tiver suporte total de todos os principais navegadores, poderemos ter um novo elemento HTML <scanner> com os recursos necessários para um leitor de código de barras. A engenharia da MishiPay acredita que há um caso de uso sólido para que a funcionalidade de leitura de código de barras seja um novo elemento HTML devido ao crescente número de bibliotecas de código aberto e licenciadas que estão permitindo experiências como Scan & Go e muitas outras.
Conclusão
A fadiga de apps é um problema que os desenvolvedores enfrentam quando seus produtos entram no mercado. Os usuários geralmente querem entender o valor que um aplicativo oferece antes de fazer o download. Em uma loja, onde a MishiPay economiza tempo dos compradores e melhora a experiência deles, é contraditório esperar um download antes de usar um aplicativo. É aí que nosso PWA ajuda.
Ao eliminar a barreira de entrada, aumentamos nossas transações em 10 vezes e permitimos que nossos usuários economizassem 2,5 anos de espera na fila.
Agradecimentos
Este artigo foi revisado por Joe Medley.