Saiba como a mudança para a PWA ajudou a MishiPay.
O MishiPay permite que os compradores façam a leitura e paguem as compras com smartphones, em vez de perder tempo na fila do caixa. Com a tecnologia Scan & Go do MishiPay, os compradores podem usar o próprio smartphone para escanear o código de barras dos itens e pagar por eles, e depois simplesmente sair da loja. Estudos revelam que as filas na loja custam ao setor de varejo global cerca de US $200 bilhões por ano.
Nossa tecnologia depende de recursos de hardware do dispositivo, como sensores de GPS e câmeras, que permitem que os usuários localizem lojas com suporte para MishiPay, leiam códigos de barras de itens na loja física e paguem usando a forma de pagamento digital de escolha. 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 migração para um PWA aumentou as transações em 10 vezes e economizou 2,5 anos de filas.
10×
Mais transações
2,5 anos
Fila salva
Desafio
Os usuários acham nossa tecnologia extremamente útil quando estão esperando na fila ou na fila de pagamento, porque ela permite que eles pulem a fila e tenham uma experiência tranquila na loja. No entanto, a dificuldade de fazer o download de 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 do usuário com uma barreira de entrada menor.
Solução
Nossos esforços para criar e lançar a PWA nos ajudaram a eliminar a dificuldade de instalação e incentivar 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, observamos um aumento significativo na adoção de usuários com nossa PWA em comparação com nossos aplicativos específicos para plataformas.
Aprofundamento técnico
Como encontrar lojas com suporte para o MishiPay
Para ativar esse recurso, usamos a API
getCurrentPosition()
com uma solução substituta 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 se mostrou um grande problema para os usuários do MishiPay pelos seguintes motivos:
- Imprecisões de localização nas soluções de substituição baseadas em IP.
- Uma lista crescente de lojas com suporte ao 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, fazendo com que as compras sejam registradas incorretamente.
Para resolver esses problemas, incorporamos QR codes com geolocalização exclusiva nas telas de cada loja. Isso facilitou a integração. Os usuários simplesmente precisam ler os códigos QR geolocalizados
impressos no material de marketing presente nas lojas para acessar o aplicativo da Web "Scan & Go".
Dessa forma, eles não precisam digitar o endereço da Web mishipay.shop
para acessar o serviço.
Como ler códigos de barras
Um recurso principal do app MishiPay é a leitura de código de barras, que permite aos usuários ler as próprias compras e conferir o total acumulado antes mesmo de chegar ao caixa registrador.
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. Invocar o 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 transmiti-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 stream de vídeo, precisamos capturar frames periodicamente e transferi-los
para a camada do decodificador. Para capturar um frame, basta desenhar os streams de VideoElement
em
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 executa algumas tarefas de pré-processamento, como recorte, 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 transferir
a tarefa que exige muito da CPU para um worker da Web. Em dispositivos com suporte à aceleração gráfica de hardware,
a API WebGL e o
WebGL2RenderingContext
podem
otimizar os ganhos nas tarefas de pré-processamento que exigem muito da CPU.
Camada do decodificador
A camada final é a camada de decodificador, que é responsável por decodificar os códigos de barras dos frames
capturados pela camada de processamento. Graças à
API Shape Detection (que ainda
não está disponível em todos os navegadores), o 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 oferecem suporte à 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
Várias bibliotecas de verificação de código aberto e corporativas estão disponíveis e podem ser facilmente integradas a qualquer aplicativo da Web para implementar a verificação. Confira algumas das bibliotecas recomendadas pela MishiPay.
Todas as bibliotecas acima são SDKs completos que compõem todas as camadas discutidas acima. Eles 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, é possível escolher entre soluções com e sem Wasm. Apesar do custo de exigir um recurso extra (Wasm) para decodificar o código de barras, as soluções Wasm são mais eficientes do que as que não usam 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 comercial. Ele supera todas as bibliotecas de código aberto disponíveis em velocidade de leitura.
Futuro da verificaçã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 equipe de 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 número crescente de bibliotecas licenciadas e de código aberto que estão permitindo
experiências como o recurso "Scan & Go" e muitas outras.
Conclusão
A fadiga de apps é um problema que os desenvolvedores enfrentam quando os produtos entram no mercado. Muitas vezes, os usuários querem entender o valor que um aplicativo oferece antes de fazer o download. Em uma loja, em que o MishiPay economiza tempo dos compradores e melhora a experiência deles, é contra-intuitivo esperar por um download antes de usar um aplicativo. É aí que nossa 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.